Ejercicios Resueltos: Archivos de Texto
Problemas y soluciones detalladas sobre streams y persistencia en C
Acerca de¶
Estos ejercicios resueltos profundizan en la manipulación y persistencia de datos usando streams de entrada/salida estándar y archivos de texto formateados en C.
Capítulos de Apunte Correspondientes¶
Cuestiones de Estilo Aplicables¶
Manejo defensivo de archivos: Asegurá siempre la validación del puntero retornado por
fopeny liberá el descriptor de archivo llamando afcloseen todas las ramas de control de errores.Validación de buffer: Evitá desbordamientos de buffer pasando siempre la capacidad límite al leer flujos con
fgets.
Ejercicio 13.1 - s Propuestos ⭐⭐☆☆☆¶
Ejercicio 13.2 - b.1 - Escribir un diario personal ⭐⭐☆☆☆¶
Solution to Exercise 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82#include <stdio.h> #include <stdlib.h> #define EXITO 0 #define ERROR -1 /** * Agrega una entrada de texto a un archivo de diario. * * @param nombre_archivo La ruta del archivo de diario. * #PRE: No puede ser NULL. * @param entrada El texto a agregar en el diario. * #PRE: No puede ser NULL. * * @returns EXITO si la entrada se escribió correctamente, ERROR en caso contrario. * * @post El archivo especificado por nombre_archivo contendrá la nueva entrada * al final del mismo, seguida de un salto de línea. */ int agregar_entrada_diario(const char *nombre_archivo, const char *entrada) { // 1. Abrir el archivo en modo "append" (añadir) FILE *p_archivo = fopen(nombre_archivo, "a"); if (p_archivo == NULL) { perror("Error al abrir el diario"); return ERROR; } // 2. Escribir la entrada if (fputs(entrada, p_archivo) == EOF) { perror("Error al escribir la entrada en el diario"); fclose(p_archivo); return ERROR; } // 3. Escribir el salto de línea if (fputc('\n', p_archivo) == EOF) { perror("Error al escribir el salto de línea"); fclose(p_archivo); return ERROR; } // 4. Cerrar el archivo if (fclose(p_archivo) != 0) { perror("Error al cerrar el diario"); return ERROR; } return EXITO; } int main(void) { const char *MI_DIARIO = "diario.txt"; int resultado = 0; printf("Escribiendo primera entrada...\n"); resultado = agregar_entrada_diario(MI_DIARIO, "Hoy fue un día soleado."); if (resultado == ERROR) { fprintf(stderr, "No se pudo escribir la primera entrada.\n"); return EXIT_FAILURE; } printf("Escribiendo segunda entrada...\n"); resultado = agregar_entrada_diario(MI_DIARIO, "Aprendí a manejar archivos en C."); if (resultado == ERROR) { fprintf(stderr, "No se pudo escribir la segunda entrada.\n"); return EXIT_FAILURE; } printf("Entradas agregadas al diario '%s' con éxito.\n", MI_DIARIO); return EXIT_SUCCESS; }
Ejercicio 13.3 - b.2 - Contador de líneas ⭐⭐⭐☆☆¶
Solution to Exercise 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86#include <stdio.h> #include <stdlib.h> #define MAX_LONGITUD_LINEA 1024 #define ERROR_APERTURA -1 #define ERROR_LECTURA -2 /** * Cuenta el número de líneas en un archivo de texto. * * @param nombre_archivo La ruta del archivo a leer. * #PRE: No puede ser NULL. * * @returns El número de líneas contadas si la operación es exitosa. * Retorna ERROR_APERTURA si el archivo no puede abrirse. * Retorna ERROR_LECTURA si ocurre un error durante la lectura. * * @post El archivo no es modificado. */ int contar_lineas(const char *nombre_archivo) { int cantidad_lineas = 0; FILE *p_archivo = NULL; char buffer[MAX_LONGITUD_LINEA]; p_archivo = fopen(nombre_archivo, "r"); if (p_archivo == NULL) { perror("Error al abrir el archivo para contar líneas"); return ERROR_APERTURA; } while (fgets(buffer, sizeof(buffer), p_archivo) != NULL) { cantidad_lineas++; } // Después del lazo, verificar si salimos por error o por fin de archivo if (ferror(p_archivo)) { perror("Error de lectura mientras se contaban las líneas"); cantidad_lineas = ERROR_LECTURA; // Sobrescribimos el conteo con un código de error } if (fclose(p_archivo) != 0) { perror("Error al cerrar el archivo después de contar"); if (cantidad_lineas >= 0) // No sobrescribir un error de lectura previo { cantidad_lineas = ERROR_APERTURA; // Reutilizamos código de error } } return cantidad_lineas; } int main(void) { const char *NOMBRE_ARCHIVO = "diario.txt"; // Crear un archivo de prueba primero FILE *p_archivo_prueba = fopen(NOMBRE_ARCHIVO, "w"); if (p_archivo_prueba != NULL) { fputs("Primera línea.\n", p_archivo_prueba); fputs("Segunda línea.\n", p_archivo_prueba); fputs("Tercera línea.\n", p_archivo_prueba); fclose(p_archivo_prueba); } printf("Contando líneas en el archivo '%s'...\n", NOMBRE_ARCHIVO); int lineas = contar_lineas(NOMBRE_ARCHIVO); if (lineas >= 0) { printf("El archivo contiene %d líneas.\n", lineas); } else { fprintf(stderr, "Ocurrió un error al procesar el archivo (código: %d).\n", lineas); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Ejercicio 13.4 - b.3 - Copiar un archivo de texto ⭐⭐☆☆☆¶
Solution to Exercise 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define EXITO 0 #define ERROR -1 #define MAX_BUFFER 4096 /** * Copia el contenido de un archivo de texto a otro. * * @param ruta_origen La ruta del archivo a leer. * #PRE: No puede ser NULL. * @param ruta_destino La ruta del archivo donde se escribirá el contenido. * #PRE: No puede ser NULL. * * @returns EXITO si la copia fue completamente exitosa, ERROR si ocurrió algún fallo. * * @post Si la operación es exitosa, el archivo en ruta_destino tendrá el mismo * contenido que el de ruta_origen. */ int copiar_archivo(const char *ruta_origen, const char *ruta_destino) { int estado_operacion = EXITO; FILE *p_origen = NULL; FILE *p_destino = NULL; char buffer[MAX_BUFFER]; bool continuar_lazo = true; p_origen = fopen(ruta_origen, "r"); if (p_origen == NULL) { perror("Error al abrir el archivo de origen"); estado_operacion = ERROR; } if (estado_operacion == EXITO) { p_destino = fopen(ruta_destino, "w"); if (p_destino == NULL) { perror("Error al abrir el archivo de destino"); estado_operacion = ERROR; } } while (estado_operacion == EXITO && continuar_lazo) { if (fgets(buffer, sizeof(buffer), p_origen) != NULL) { if (fputs(buffer, p_destino) == EOF) { perror("Error al escribir en el archivo de destino"); estado_operacion = ERROR; } } else { continuar_lazo = false; // Se terminó de leer o hubo un error } } // Verificar si el lazo terminó por un error de lectura if (p_origen != NULL && ferror(p_origen)) { perror("Error de lectura en el archivo de origen"); estado_operacion = ERROR; } // Cerrar ambos archivos, verificando errores en cada cierre if (p_origen != NULL && fclose(p_origen) != 0) { perror("Error al cerrar el archivo de origen"); estado_operacion = ERROR; } if (p_destino != NULL && fclose(p_destino) != 0) { perror("Error al cerrar el archivo de destino"); estado_operacion = ERROR; } return estado_operacion; } int main(void) { const char *ARCHIVO_ORIGEN = "original.txt"; const char *ARCHIVO_COPIA = "copia.txt"; // Crear archivo original de prueba FILE *p_temp = fopen(ARCHIVO_ORIGEN, "w"); if (p_temp != NULL) { fprintf(p_temp, "Línea 1 del original.\n"); fprintf(p_temp, "Línea 2 con algunos caracteres especiales: áéíóú.\n"); fprintf(p_temp, "Fin del archivo original.\n"); fclose(p_temp); } printf("Copiando '%s' a '%s'...\n", ARCHIVO_ORIGEN, ARCHIVO_COPIA); if (copiar_archivo(ARCHIVO_ORIGEN, ARCHIVO_COPIA) == EXITO) { printf("Archivo copiado con éxito.\n"); } else { fprintf(stderr, "La copia del archivo falló.\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; }
Ejercicio 13.5 - b.4 - Registrar eventos en un log ⭐⭐☆☆☆¶
Solution to Exercise 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75#include <stdio.h> #include <stdlib.h> #define EXITO 0 #define ERROR -1 #define ARCHIVO_LOG "eventos.log" /** * Registra un mensaje de evento en un archivo de log. * * @param mensaje El mensaje a registrar. * #PRE: No puede ser NULL. * * @returns EXITO si el evento se registró correctamente, ERROR en caso contrario. * * @post El archivo de log contendrá el nuevo mensaje al final. */ int registrar_evento(const char *mensaje) { int resultado = EXITO; FILE *p_log = fopen(ARCHIVO_LOG, "a"); if (p_log == NULL) { perror("Error al abrir el archivo de log"); resultado = ERROR; } else { // Escribir el mensaje y un salto de línea if (fprintf(p_log, "%s\n", mensaje) < 0) { perror("Error al escribir en el archivo de log"); resultado = ERROR; } // Cerrar el archivo if (fclose(p_log) != 0) { perror("Error al cerrar el archivo de log"); resultado = ERROR; } } return resultado; } int main(void) { printf("Registrando eventos...\n"); if (registrar_evento("[INFO] El sistema ha iniciado.") != EXITO) { fprintf(stderr, "Fallo al registrar el primer evento.\n"); return EXIT_FAILURE; } if (registrar_evento("[WARN] El disco está casi lleno.") != EXITO) { fprintf(stderr, "Fallo al registrar el segundo evento.\n"); return EXIT_FAILURE; } if (registrar_evento("[FATAL] No se pudo conectar a la base de datos.") != EXITO) { fprintf(stderr, "Fallo al registrar el tercer evento.\n"); return EXIT_FAILURE; } printf("Eventos registrados en '%s'.\n", ARCHIVO_LOG); return EXIT_SUCCESS; }