Ejercicios Resueltos: Archivos de Texto
Problemas y soluciones detalladas sobre streams y persistencia en C
Prerrequisitos y Entorno Requerido¶
Para abordar y verificar las soluciones de persistencia de este módulo, se requiere:
Entorno de Compilación: Compilador GCC 9+ o Clang configurado en estándar estricto ISO C11 (
-std=c11 -Wall -Wextra -Werror -pedantic).Conceptos de E/S Estándar: Manejo seguro de flujos (
FILE *), modos de apertura ("r","w","a"), buffers confgets, escritura confputs/fprintfy cierre estricto confclose.Manejo Defensivo de Recursos: Validación de punteros de archivo nulos y eliminación sistemática de artefactos temporales en pruebas mediante
remove().
Acerca de¶
Estos ejercicios profundizan en la manipulación, lectura formateada, escritura y
persistencia de datos usando streams estándar de E/S (FILE *) en C11.
Capítulos de Apunte Correspondientes¶
Ejercicio 2.04b.01 - Escritura de Entradas en 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#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define EXITO 0 #define ERROR -1 int agregar_entrada_diario(const char *nombre_archivo, const char *entrada) { if (nombre_archivo == NULL || entrada == NULL) { return ERROR; } FILE *p_archivo = fopen(nombre_archivo, "a"); if (p_archivo == NULL) { return ERROR; } if (fputs(entrada, p_archivo) == EOF) { fclose(p_archivo); return ERROR; } if (fputc('\n', p_archivo) == EOF) { fclose(p_archivo); return ERROR; } if (fclose(p_archivo) != 0) { return ERROR; } return EXITO; } int main(void) { const char *test_file = "test_diario_tmp.txt"; remove(test_file); // Caso normal assert(agregar_entrada_diario(test_file, "Primera entrada") == EXITO); // Caso múltiple assert(agregar_entrada_diario(test_file, "Segunda entrada") == EXITO); // Caso cadena vacía assert(agregar_entrada_diario(test_file, "") == EXITO); // Caso punteros nulos assert(agregar_entrada_diario(NULL, "Texto") == ERROR); assert(agregar_entrada_diario(test_file, NULL) == ERROR); // Verificar contenido persistido FILE *f = fopen(test_file, "r"); assert(f != NULL); char buf[128]; assert(fgets(buf, sizeof(buf), f) != NULL); assert(strcmp(buf, "Primera entrada\n") == 0); assert(fgets(buf, sizeof(buf), f) != NULL); assert(strcmp(buf, "Segunda entrada\n") == 0); assert(fgets(buf, sizeof(buf), f) != NULL); assert(strcmp(buf, "\n") == 0); fclose(f); remove(test_file); return 0; }
Ejercicio 2.04b.02 - Conteo Seguro de Líneas en Archivo de Texto ⭐⭐⭐☆☆¶
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#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LONGITUD_LINEA 1024 #define ERROR_APERTURA -1 #define ERROR_LECTURA -2 int contar_lineas(const char *nombre_archivo) { if (nombre_archivo == NULL) { return ERROR_APERTURA; } FILE *p_archivo = fopen(nombre_archivo, "r"); if (p_archivo == NULL) { return ERROR_APERTURA; } int cantidad_lineas = 0; char buffer[MAX_LONGITUD_LINEA]; while (fgets(buffer, sizeof(buffer), p_archivo) != NULL) { cantidad_lineas++; } if (ferror(p_archivo)) { fclose(p_archivo); return ERROR_LECTURA; } fclose(p_archivo); return cantidad_lineas; } int main(void) { const char *test_file = "test_contar_tmp.txt"; // Caso 3 líneas FILE *f = fopen(test_file, "w"); assert(f != NULL); fputs("Linea 1\nLinea 2\nLinea 3\n", f); fclose(f); assert(contar_lineas(test_file) == 3); // Caso archivo vacío f = fopen(test_file, "w"); assert(f != NULL); fclose(f); assert(contar_lineas(test_file) == 0); // Caso 1 línea f = fopen(test_file, "w"); assert(f != NULL); fputs("Unica linea\n", f); fclose(f); assert(contar_lineas(test_file) == 1); // Caso archivo inexistente assert(contar_lineas("archivo_inexistente_999.txt") == ERROR_APERTURA); remove(test_file); return 0; }
Ejercicio 2.04b.03 - Copia Robusta de 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#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define EXITO 0 #define ERROR -1 #define MAX_BUFFER 1024 int copiar_archivo(const char *origen, const char *destino) { if (origen == NULL || destino == NULL || strcmp(origen, destino) == 0) { return ERROR; } FILE *f_orig = fopen(origen, "r"); if (f_orig == NULL) { return ERROR; } FILE *f_dest = fopen(destino, "w"); if (f_dest == NULL) { fclose(f_orig); return ERROR; } char buffer[MAX_BUFFER]; int estado = EXITO; while (fgets(buffer, sizeof(buffer), f_orig) != NULL) { if (fputs(buffer, f_dest) == EOF) { estado = ERROR; break; } } if (ferror(f_orig)) { estado = ERROR; } fclose(f_orig); if (fclose(f_dest) != 0) { estado = ERROR; } return estado; } int main(void) { const char *orig = "test_copia_orig.txt"; const char *dest = "test_copia_dest.txt"; // Caso normal FILE *f = fopen(orig, "w"); assert(f != NULL); fputs("Línea uno de prueba.\nLínea dos.\n", f); fclose(f); assert(copiar_archivo(orig, dest) == EXITO); FILE *fd = fopen(dest, "r"); assert(fd != NULL); char buf[128]; assert(fgets(buf, sizeof(buf), fd) != NULL); assert(strcmp(buf, "Línea uno de prueba.\n") == 0); assert(fgets(buf, sizeof(buf), fd) != NULL); assert(strcmp(buf, "Línea dos.\n") == 0); fclose(fd); // Caso error mismo archivo assert(copiar_archivo(orig, orig) == ERROR); // Caso error origen inexistente assert(copiar_archivo("no_existe.txt", dest) == ERROR); remove(orig); remove(dest); return 0; }
Ejercicio 2.04b.04 - Registro de Eventos con Marca de Nivel en Archivo 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#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define EXITO 0 #define ERROR -1 int registrar_log(const char *archivo_log, const char *nivel, const char *mensaje) { if (archivo_log == NULL || nivel == NULL || mensaje == NULL) { return ERROR; } FILE *p_log = fopen(archivo_log, "a"); if (p_log == NULL) { return ERROR; } if (fprintf(p_log, "[%s] %s\n", nivel, mensaje) < 0) { fclose(p_log); return ERROR; } if (fclose(p_log) != 0) { return ERROR; } return EXITO; } int main(void) { const char *log_file = "test_eventos_tmp.log"; remove(log_file); // Casos normales assert(registrar_log(log_file, "INFO", "Sistema iniciado") == EXITO); assert(registrar_log(log_file, "ERROR", "Fallo de red") == EXITO); // Casos nulos assert(registrar_log(NULL, "INFO", "Mensaje") == ERROR); assert(registrar_log(log_file, NULL, "Mensaje") == ERROR); assert(registrar_log(log_file, "INFO", NULL) == ERROR); // Verificar contenido FILE *f = fopen(log_file, "r"); assert(f != NULL); char buf[128]; assert(fgets(buf, sizeof(buf), f) != NULL); assert(strcmp(buf, "[INFO] Sistema iniciado\n") == 0); assert(fgets(buf, sizeof(buf), f) != NULL); assert(strcmp(buf, "[ERROR] Fallo de red\n") == 0); fclose(f); remove(log_file); return 0; }
Ejercicio 2.04b.05 - Procesamiento y Suma Total de Ventas en CSV ⭐⭐☆☆☆¶
Solution to Exercise 5
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#include <assert.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_LINEA 256 #define MAX_PRODUCTO 100 double calcular_total_ventas_csv(const char *nombre_archivo) { if (nombre_archivo == NULL) { return -1.0; } FILE *p_archivo = fopen(nombre_archivo, "r"); if (p_archivo == NULL) { return -1.0; } char buffer[MAX_LINEA]; double total_acumulado = 0.0; while (fgets(buffer, sizeof(buffer), p_archivo) != NULL) { if (buffer[0] == '\n' || buffer[0] == '#' || buffer[0] == '\r') { continue; } char nombre[MAX_PRODUCTO]; double precio = 0.0; int cantidad = 0; int leidos = sscanf(buffer, "%99[^,],%lf,%d", nombre, &precio, &cantidad); if (leidos == 3 && precio >= 0.0 && cantidad >= 0) { total_acumulado += precio * (double)cantidad; } } fclose(p_archivo); return total_acumulado; } int main(void) { const char *csv_file = "test_ventas_tmp.csv"; FILE *f = fopen(csv_file, "w"); assert(f != NULL); fputs("Teclado Mecanico,100.0,2\n", f); fputs("# Comentario de encabezado\n", f); fputs("\n", f); fputs("Mouse Gamer,50.0,3\n", f); fputs("Webcam,precio_corrupto,1\n", f); fclose(f); double total = calcular_total_ventas_csv(csv_file); assert(fabs(total - 350.0) < 0.001); // Caso archivo inexistente assert(calcular_total_ventas_csv("inexistente.csv") < 0.0); remove(csv_file); return 0; }
Ejercicio 2.04b.06 - Inversión Carácter por Carácter con fseek ⭐⭐⭐☆☆¶
Solution to Exercise 6
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 114#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define EXITO 0 #define ERROR -1 int invertir_archivo(const char *origen, const char *destino) { if (origen == NULL || destino == NULL || strcmp(origen, destino) == 0) { return ERROR; } FILE *f_orig = fopen(origen, "rb"); if (f_orig == NULL) { return ERROR; } if (fseek(f_orig, 0, SEEK_END) != 0) { fclose(f_orig); return ERROR; } long tamano = ftell(f_orig); if (tamano < 0) { fclose(f_orig); return ERROR; } FILE *f_dest = fopen(destino, "wb"); if (f_dest == NULL) { fclose(f_orig); return ERROR; } for (long i = 1; i <= tamano; i++) { if (fseek(f_orig, -i, SEEK_END) != 0) { fclose(f_orig); fclose(f_dest); return ERROR; } int c = fgetc(f_orig); if (c == EOF) { fclose(f_orig); fclose(f_dest); return ERROR; } if (fputc(c, f_dest) == EOF) { fclose(f_orig); fclose(f_dest); return ERROR; } } fclose(f_orig); if (fclose(f_dest) != 0) { return ERROR; } return EXITO; } int main(void) { const char *orig = "test_inv_orig.txt"; const char *dest = "test_inv_dest.txt"; // Caso normal FILE *f = fopen(orig, "wb"); assert(f != NULL); fputs("ABC", f); fclose(f); assert(invertir_archivo(orig, dest) == EXITO); FILE *fd = fopen(dest, "rb"); assert(fd != NULL); char buf[16] = {0}; assert(fread(buf, 1, 3, fd) == 3); assert(strcmp(buf, "CBA") == 0); fclose(fd); // Caso un caracter f = fopen(orig, "wb"); assert(f != NULL); fputs("X", f); fclose(f); assert(invertir_archivo(orig, dest) == EXITO); fd = fopen(dest, "rb"); assert(fd != NULL); memset(buf, 0, sizeof(buf)); assert(fread(buf, 1, 1, fd) == 1); assert(strcmp(buf, "X") == 0); fclose(fd); remove(orig); remove(dest); return 0; }