Archivos

Archivos de texto

  1. Implementá una función que lea una línea (cadena de caracteres) de largo indefinido (de cualquier FILE *) y la retorne por el nombre. Implementar otra función que realice lo mismo, pero retornando la cadena leída por la interfaz y si todo salió bien por el nombre. Prototipos:

    char * readline(FILE *);
    bool readline(FILE *, char **);
    

    La función se puede implementar tanto con fgetc() como con fgets(). Hacerlo de ambas maneras.

  2. Escriba un programa que guarde todo lo que el usuario escriba mientras no escriba una cadena centinela pasada como argumento:

    $ ./editor texto.txt "hasta la victoria"
    *** Guardaré todo lo que escribas en el archivo: texto.txt ***
    *** Para terminar, el centinela es: hasta la victoria      ***
    Ayer te vi que subías
    por el camino a la fuente
    dime dónde vas, morena
    dime dónde vas, salada.
    hasta la victoria
    *** Hasta acá llegamos ***
    
  3. Escriba un programa que copie un archivo de texto. Utilice argumentos en línea de comandos para indicar el archivo de entrada y el archivo de salida.

  4. Escriba un programa que lea un archivo de texto y lo imprima, agregando en número de línea al comienzo:

    $ ./numerar texto.txt
    1: Ayer te vi que subías
    2: por el camino a la fuente
    3: dime dónde vas, morena
    4: dime dónde vas, salada.
    

    Opcional: agregue un argumento al programa para indicar en qué número debe comenzar a imprimir. Interpretación libre.

  5. Escriba un programa que cuente la cantidad de líneas de un archivo, si el programa recibe el argumento -l. Opcionalmente, agregue al programa la posibilidad de contar palabras si recibe el argumento -w y bytes si recibe el argumento -c. Si recibe más de un archivo como argumento, imprime los totales, como se muestra a continuación:

    $ ./mi_wc -l texto.txt
    4 texto.txt
    $ ./mi_wc -c texto.txt
    98 texto.txt
    $ ./mi_wc -w texto.txt
    19 texto.txt
    $ ./mi_wc -l -c -w texto.txt
     4 19 98 texto.txt
    $ ./mi_wc -c -w -l texto.txt
     4 19 98 texto.txt
    $ ./mi_wc -w -l -c texto.txt completa.txt
      4  19  98 texto.txt
     16  78 404 completa.txt
     20  97 502 total
    
  6. Escriba un programa que lea uno o varios archivos de texto e imprima únicamente las líneas del mismo que contengan una determinada palabra pasada como primer argumento al programa:

    $ ./mi_grep morena texto.txt
    dime dónde vas, morena
    $ ./mi_grep morena texto.txt completa.txt
    texto.txt:dime dónde vas, morena
    completa.txt:dime dónde vas, morena
    completa.txt:Dime dónde vas, morena
    completa.txt:dime dónde vas, morena
    $ ./mi_grep modelo texto.txt completa.txt
    completa.txt:Voy a la cárcel modelo
    

    Opcional: permita que programa reciba un argumento, -n, que indique que se desea imprimir el número de línea correspondiente.

    $ ./mi_grep -n morena texto.txt completa.txt
    texto.txt:3:dime dónde vas, morena
    completa.txt:3:dime dónde vas, morena
    completa.txt:9:Dime dónde vas, morena
    completa.txt:11:dime dónde vas, morena
    
  7. Escriba un programa que reciba 2 cadenas, nueva y vieja, y reemplace todas las ocurrencias de vieja por nueva, en los archivos pasados como argumento.

    $ ./mi_sed "vieja frase" "somos progre" archivo.txt archivo.tex
    

Archivos binarios

  1. Escribí un programa que genere un archivo binario grabando en él los números enteros del 0 al 1000000.

  2. Escribí un programa que cargue un vector de enteros con los números almacenados en el archivo generado en el punto anterior.

    1. Escribí el programa asumiendo que conocés la cantidad de números a leer.

    2. Escribí el programa asumiendo que no conocés la cantidad de números a leer.

  3. Dada la definición de la estructura materia_t como se muestra a continuación

    struct materia {
        unsigned char codigo_departamento;
        unsigned char codigo_materia;
        char nombre[100];
    };
    typedef struct materia materia_t;
    

    Cargar un vector de materias y:

    1. Guardá ese vector en un archivo binario; después levantalo a un vector dinámico y ordenalo por departamento.

    2. Repetí el proceso cargando el archivo en un vector de punteros a estructuras.

    3. Con el vector del punto anterior, guardá en un nuevo archivo sólo las materias de un determinado departamento.

  4. Dada las siguientes definiciones para una persona

    struct direccion {
        char provincia[56];
        char ciudad[20];
        char calle[30];
        int numero;
        char unidad[7];
        char cpa[10];
    };
    
    /* definí el enum genero según tu preferecia */
    typedef enum genero genero_t;
    
    struct persona {
        char * nombre;
        char * apellido;
        genero_t genero;
        int edad;
        struct direccion * direccion;
    };
    typedef struct persona persona_t;
    
    1. Escribí un programa que cargue un vector de punteros a estructuras de tipo persona_t. Para hacerlo, seguí una de las siguientes estrategias:

      • generá un número aleatorio entero entre 1 y 3 y cargá esa cantidad, luego generá otro número aleatorio entre 0 y 1.0, si es mayor a 0.1, repetí el proceso. Hacelo hasta que el número aleatorio sea menor a 0.1. Las estructuras son generadas con datos aleatorios (seguramente sin sentido).

      • pedile todos los datos a la persona que ejecute el programa, para que ingrese una a una las personas de la lista. El ingreso finaliza cuando se ingresa un centinela.

    2. Con el vector de estructuras cargado, guardalas en un archivo binario recibido como parámetro del programa. Considerá que el archivo ya puede tener otros datos.

    3. Escribí un programa que cargue los datos almacenados en un archivo binario como el generado en el inciso anterior e imprima por pantalla únicamente aquellas personas que cumplan:

      • su edad cumple con algún criterio pasado como argumento,

      • su género cumple con algún criterio pasado como argumento,

      • su país cumple con algún criterio pasado como argumento.

      Pueden ser 3 programas distintos. ¿Cómo lo invocarías?

Aplicación

En Construcción

  1. En este ejercicio y en este otro ejercicio procesamos líneas con campos de ancho fijo. Siguiendo esa línea, vamos (vas) a escribir un programa que procese un archivo con campos de ancho fijo. Para ello, vamos a suponer que lo que tenemos que mantener es un software de transacciones bancarias.

    Un archivo, transacciones.log, contiene líneas con campos de ancho fijo. Cada línea contiene 22 dígitos que corresponden a un CBU [1] de origen, luego 22 dígitos que corresponden al CBU destino, y luego 10 dígitos que corresponden al monto transferido en centavos. Sin embargo, se ha decidido que para evitar transacciones fraudulentas, el monto máximo a transferir sea 42949672.95 y no puede ser negativo ni cero. Un ejemplo de una línea válida es:

    285059094009041813520128505909400904181352020000052395
    

    Un CBU está compuesto por 3 dígitos que corresponden a la entidad bancaria, 4 dígitos que corresponden a la sucursal, 1 dígito verificador (que ignoraremos), 13 dígitos del número de cuenta y 1 dígito verificador de cuenta (que ignoraremos). Como se muestra en la imagen siguiente, tomada de wikipedia.

    Ejemplo CBU

    Figura 1 Ejemplo de un CBU. Fuente: wikipedia/CBU

    Otro archivo, cuentas.dat, contiene estructuras que representan una cuenta bancaria, según la estructura cuenta_t más abajo.

    typedef struct {
        int entidad;
        int sucursal;
        long int cuenta;
    } cbu_t;
    
    typedef struct {
        char provincia[STR_PROVINCIA_MAX];
        char ciudad[STR_CIUDAD_MAX];
        char calle[STR_CALLE_MAX];
        int numero;
        char unidad[STR_UNIDAD_MAX];
        char cpa[STR_CPA_MAX];
    } direccion_t;
    
    typedef struct {
        cbu_t cbu;
        long int saldo;
        direccion_t direccion;
        char nombre[STR_NOMBRE_MAX];
    } cuenta_t;
    
    typedef struct {
        cbu_t cbu_origen;
        cbu_t cbu_destino;
        long int monto;
    } transaccion_t;
    

    Escriba un programa que lea el archivo transacciones.log y actualice los registros almacenados en cuentas.dat.

    ¿Qué ocurre si en lugar de utilizar los CBUs se utilizan los índices del registro dentro del archivo para almacenar las transacciones?. Por ejemplo, un archivo puede tener 100 registros, y una transacción almacenada como:

    0210520000052395
    

    representa una transacción de 523.95 pesos de la cuenta 21 a la cuenta 52.

  2. En este ejercicio y este otro ejercicio procesamos líneas con campos separados por delimitadores (comas en particular).

    http://www.gpsinformation.org/dale/nmea.htm

    $GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76
    $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
    $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
    $GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79
    $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
    $GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43
    $GPGGA,092751.000,5321.6802,N,00630.3371,W,1,8,1.03,61.7,M,55.3,M,,*75
    $GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
    $GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
    $GPGSV,3,2,11,02,39,223,16,13,28,070,17,26,23,252,,04,14,186,15*77
    $GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
    $GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45
    
    typedef struct nmea_time {
        int year;
        int mon;
        int day;
        int hour;
        int min;
        int sec;
        int hsec;
    } nmea_time;
    
    typedef struct nmea_gga {
        nmea_time utc;
        double  lat;
        double  lon;
        int     fix_quality;
        int     satellites;
        double  HDOP;
        double  elv;
        double  diff;
        double  dgps_age;
        int     dgps_sid;
    } nmea_gga;