Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Ejercicios de Archivos

Universidad Nacional de Río Negro

Prerrequisitos y Entorno Requerido

Para abordar y verificar las soluciones de este módulo, se requiere:

  1. Entorno de Compilación: Compilador GCC 9+ o Clang bajo estándar estricto ISO C11 (-std=c11 -Wall -Wextra -Werror -pedantic).

  2. Flujos de Persistencia Estándar: Manejo de descriptores FILE *, modos de apertura ("r", "w", "a"), verificación mandatoria contra NULL y cierre estricto de recursos con fclose.

  3. Control Seguro de Lectura: Validación defensiva mediante retorno de fgets/fscanf, prevención del antipatrón while (!feof()) y eliminación de archivos de prueba temporales con remove().

Acerca de

Estos ejercicios tienen como fin practicar la interacción de los programas con dispositivos de almacenamiento mediante streams y archivos de texto formateados en C.

Capítulos de Apunte Correspondientes


Herramientas y Verificación

Para los siguientes ejercicios, se trabajará con archivos de texto que contienen números enteros, uno por línea. El primer número del archivo indica la cantidad total de números que le siguen.

Ejemplo numeros.txt:

1
2
3
4
5
6
5
3
-5
3
6
3

En este ejemplo, el 5 inicial indica que hay 5 números a continuación.

Ejercicio 2.04.01 - ¿Es correcto el formato? ⭐⭐☆☆☆


(ej_b2_c04_02)=
### Ejercicio 2.04.02 - ¿Está ordenado? ⭐⭐☆☆☆

:::{exercise}
:label: ej_b2_c04_02_verificar_orden

Implementá una función `int verificar_orden(const char *ruta)` que determine si
los números contenidos en el archivo están ordenados:
- Retorna `1` si la secuencia de $N$ números es estrictamente ascendente o no decreciente ($v_i \le v_{i+1}$).
- Retorna `-1` si es estrictamente descendente o no creciente ($v_i \ge v_{i+1}$).
- Retorna `0` si está desordenada.
- Retorna `-2` ante error de archivo o formato inválido.

::::{solution}
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

int verificar_orden(const char *ruta) {
    if (ruta == NULL) {
        return -2;
    }
    FILE *f = fopen(ruta, "r");
    if (f == NULL) {
        return -2;
    }

    int n = 0;
    if (fscanf(f, "%d", &n) != 1 || n < 0) {
        fclose(f);
        return -2;
    }

    if (n <= 1) {
        fclose(f);
        return 1; /* Secuencia trivialmente ordenada */
    }

    int anterior = 0;
    if (fscanf(f, "%d", &anterior) != 1) {
        fclose(f);
        return -2;
    }

    bool es_asc = true;
    bool es_desc = true;
    int actual = 0;

    for (int i = 1; i < n; ++i) {
        if (fscanf(f, "%d", &actual) != 1) {
            fclose(f);
            return -2;
        }
        if (actual < anterior) {
            es_asc = false;
        }
        if (actual > anterior) {
            es_desc = false;
        }
        anterior = actual;
    }

    fclose(f);

    if (es_asc) return 1;
    if (es_desc) return -1;
    return 0;
}

static void crear_archivo(const char *ruta, const char *contenido) {
    FILE *f = fopen(ruta, "w");
    assert(f != NULL);
    fputs(contenido, f);
    fclose(f);
}

int main(void) {
    const char *f_asc = "temp_asc.txt";
    const char *f_desc = "temp_desc.txt";
    const char *f_desord = "temp_desord.txt";

    crear_archivo(f_asc, "4\n1\n3\n5\n7\n");
    crear_archivo(f_desc, "4\n9\n6\n4\n2\n");
    crear_archivo(f_desord, "4\n3\n8\n2\n9\n");

    assert(verificar_orden(f_asc) == 1);
    assert(verificar_orden(f_desc) == -1);
    assert(verificar_orden(f_desord) == 0);
    assert(verificar_orden("inexistente_999.txt") == -2);
    assert(verificar_orden(NULL) == -2);

    remove(f_asc);
    remove(f_desc);
    remove(f_desord);
    return 0;
}
```

---

## Manipulación de Archivos

(ej_b2_c04_03)=
### Ejercicio 2.04.03 - Ordenar archivo ⭐⭐☆☆☆

Un programa que lea los números de un archivo a un arreglo, ordene el arreglo en
memoria y luego escriba el contenido ordenado a un nuevo archivo, respetando el
formato.

**Ejemplo de uso:**
`./ordena_archivo entrada.txt salida_ordenada.txt asc`

(ej_b2_c04_04)=
### Ejercicio 2.04.04 - Generador Lineal de Archivos ⭐⭐☆☆☆

:::{exercise}
:label: ej_b2_c04_04_generador_lineal

Implementá una función `bool generar_lineal(const char *ruta, int cantidad, int inicio, int paso)` que genere un archivo numérico formateado:
1. La primera línea registra `cantidad`.
2. Las líneas subsiguientes registran los valores en progresión aritmética: $inicio + i \times paso$.
3. Retorna `true` si la escritura finalizó con éxito y `false` ante parámetros inválidos (`cantidad < 0` o `ruta == NULL`) o error de apertura.

**Tabla de Vectores de Prueba:**

| Parámetros `(cantidad, inicio, paso)` | Retorno Esperado | Contenido Escrito |
| :--- | :--- | :--- |
| `(5, 10, 2)` | `true` | `5\n10\n12\n14\n16\n18\n` |
| `(0, 5, 1)` | `true` | `0\n` |
| `(-3, 1, 1)` | `false` | No crea archivo |
| `(4, 0, 0)` | `true` | `4\n0\n0\n0\n0\n` |

::::{solution}
```c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

bool generar_lineal(const char *ruta, int cantidad, int inicio, int paso) {
    if (ruta == NULL || cantidad < 0) {
        return false;
    }
    FILE *f = fopen(ruta, "w");
    if (f == NULL) {
        return false;
    }

    if (fprintf(f, "%d\n", cantidad) < 0) {
        fclose(f);
        return false;
    }

    int val = inicio;
    for (int i = 0; i < cantidad; ++i) {
        if (fprintf(f, "%d\n", val) < 0) {
            fclose(f);
            return false;
        }
        val += paso;
    }

    fclose(f);
    return true;
}

int main(void) {
    const char *tmp = "temp_lineal_test.txt";

    assert(generar_lineal(tmp, 5, 10, 2) == true);

    /* Verificar lectura */
    FILE *f = fopen(tmp, "r");
    assert(f != NULL);
    int n = 0;
    assert(fscanf(f, "%d", &n) == 1 && n == 5);
    int esperados[] = {10, 12, 14, 16, 18};
    for (int i = 0; i < 5; ++i) {
        int v = 0;
        assert(fscanf(f, "%d", &v) == 1 && v == esperados[i]);
    }
    fclose(f);
    remove(tmp);

    /* Casos defensivos */
    assert(generar_lineal(NULL, 5, 1, 1) == false);
    assert(generar_lineal("temp_invalido.txt", -2, 1, 1) == false);

    return 0;
}
```

(ej_b2_c04_05)=
### Ejercicio 2.04.05 - Generador aleatorio ⭐⭐☆☆☆

Implementar `generar_aleatorio(ruta, cantidad, min, max)`.

**Lógica**: Usar `srand(time(NULL))` una vez al inicio del programa, y luego
`rand() % (max - min + 1) + min` para generar cada número.

---

## Operaciones Avanzadas

(ej_b2_c04_06)=
### Ejercicio 2.04.06 - Contar Líneas, Palabras y Caracteres ⭐⭐☆☆☆

Implementar una versión simple del comando `wc` de Unix. El programa debe
recibir una ruta de archivo y reportar el número total de líneas, palabras y
caracteres que contiene.

(ej_b2_c04_07)=
### Ejercicio 2.04.07 - Copiar Archivo ⭐⭐☆☆☆

Crear un programa que copie el contenido de un archivo de origen a un archivo de
destino. El programa debe recibir ambas rutas como argumentos. Se puede hacer
leyendo y escribiendo línea por línea o en bloques de bytes.

(ej_b2_c04_08)=
### Ejercicio 2.04.08 - Buscar y Reemplazar en Archivo ⭐⭐☆☆☆

Escribir un programa que busque todas las ocurrencias de una cadena en un
archivo y las reemplace por otra, guardando el resultado en un nuevo archivo de
salida.

(ej_b2_c04_09)=
### Ejercicio 2.04.09 - Comparar Archivos ⭐⭐⭐☆☆

Implementar un programa que compare dos archivos de texto e indique si son
idénticos o no. Opcionalmente, puede reportar la primera línea y número de
columna donde difieren.

(ej_b2_c04_10)=
### Ejercicio 2.04.10 - Fusionar Archivos ⭐⭐⭐☆☆

Crear un programa que reciba dos rutas de archivo y fusione su contenido en un
tercer archivo. El contenido del segundo archivo debe aparecer después del
contenido del primero.

(ej_b2_c04_11)=
### Ejercicio 2.04.11 - Dividir Archivo Grande ⭐⭐☆☆☆

Escribir un programa que divida un archivo de texto grande en varios archivos
más pequeños, cada uno con un número máximo de $N$ líneas. Los nombres de los
archivos de salida pueden ser `parte_1.txt`, `parte_2.txt`, etc.

(ej_b2_c04_12)=
### Ejercicio 2.04.12 - Archivos CSV - Promedio de Columna ⭐⭐⭐☆☆

Leer un archivo en formato CSV (valores separados por comas) que contiene datos
de estudiantes (ej. `nombre,nota1,nota2`). Calcular el promedio de una columna
numérica específica (ej. la segunda columna de notas) e imprimir el resultado.

(ej_b2_c04_13)=
## Ejercicio 2.04.13 - Crear Archivo de Texto ⭐☆☆☆☆

Creá un archivo de texto y escribí "Hola, archivo!" en él.

**Orientación:**
- `FILE *fp = fopen("salida.txt", "w");`
- Verificá: `if (fp == NULL) { perror("Error"); return 1; }`
- Escribí: `fprintf(fp, "Hola, archivo!\n");`
- Cerrá: `fclose(fp);`

---

(ej_b2_c04_14)=
## Ejercicio 2.04.14 - Leer Archivo Completo ⭐☆☆☆☆

Leé y mostrá todo el contenido de un archivo de texto.

**Orientación:**
- Abrí en modo "r"
- Leé línea por línea con `fgets(buffer, tamaño, fp)`
- Mientras no sea EOF: `while (fgets(...) != NULL)`
- Mostrá cada línea en stdout

---

(ej_b2_c04_15)=
### Ejercicio 2.04.15 - Conteo Robusto de Líneas en Archivo de Texto ⭐⭐☆☆☆

:::{exercise}
:label: ej_b2_c04_15_contar_lineas
:enumerator: archivos-15

Implementá una función defensiva que cuente la cantidad de líneas en un archivo de texto:
```c
long contar_lineas_archivo(const char *ruta);
```
La función debe leer el archivo carácter por carácter utilizando `fgetc`.
Una línea se delimita por el carácter `'\n'`. Si el archivo contiene datos pero el último registro no finaliza con `'\n'`, esa última línea también debe ser contabilizada. Si el archivo está completamente vacío ($0$ bytes), debe retornar `0`. Si `ruta == NULL` o el archivo no puede abrirse, debe retornar `-1`.

**Nivel de Bloom:** Nivel 3 (Aplicación).  
**Conceptos requeridos:** Flujos de entrada de texto (`FILE *`, `fgetc`), detección de fin de archivo (`EOF`), manejo de casos sin delimitador final.  
**Techo conceptual:** Prohibido el uso de memoria dinámica innecesaria o cargar todo el archivo en un búfer.

#### Contrato de la Función
- **Firma:** `long contar_lineas_archivo(const char *ruta);`
- **Precondiciones:** `ruta != NULL`.
- **Postcondiciones:** Retorna el número de líneas $\ge 0$, o `-1` ante error de apertura. Todo archivo abierto debe cerrarse con `fclose`.

#### Tabla de Vectores de Prueba

| Contenido del Archivo | Retorno Esperado | Justificación Técnica |
| :--- | :--- | :--- |
| `"Uno\nDos\nTres\n"` | `3` | Tres líneas terminadas con `'\n'` |
| `"Linea unica sin salto"` | `1` | Archivo con texto sin salto final |
| `""` (0 bytes) | `0` | Archivo vacío |
| Archivo inexistente / `NULL` | `-1` | Error defensivo de apertura |

Ejercicio 2.04.16 - Copiar Archivo ⭐⭐☆☆☆

Copiá el contenido de un archivo a otro.

Orientación:


Ejercicio 2.04.17 - Contar Palabras ⭐⭐⭐☆☆

Contá la cantidad de palabras en un archivo de texto.

Orientación:


Ejercicio 2.04.18 - Agregar al Final ⭐⭐☆☆☆

Agregá texto al final de un archivo existente sin sobrescribir.

Orientación:


Ejercicio 2.04.19 - Buscar Palabra ⭐⭐⭐☆☆

Buscá si una palabra específica existe en un archivo y mostrá la línea.

Orientación:


Ejercicio 2.04.20 - Estadísticas de Archivo ⭐⭐⭐☆☆

Calculá: líneas, palabras, caracteres y bytes de un archivo.

Orientación:


Ejercicio 2.04.21 - Invertir Líneas ⭐⭐⭐⭐☆

Leé un archivo y escribí sus líneas en orden inverso en otro archivo.

Orientación:


Ejercicio 2.04.22 - Archivo CSV a Struct ⭐⭐⭐⭐☆

Leé un archivo CSV con datos de personas y cargá en array de estructuras.

Formato CSV:

Juan,Perez,25
Maria,Gomez,30

Orientación:


Ejercicio 2.04.23 - Merge de Archivos Ordenados ⭐⭐⭐⭐☆

Dados dos archivos con números ordenados, generá un tercer archivo con todos ordenados.

Orientación:


Ejercicio 2.04.24 - Reemplazar Palabra ⭐⭐⭐⭐☆

Reemplazá todas las ocurrencias de una palabra por otra en un archivo.

Orientación:


Ejercicio 2.04.25 - Archivo Binario - Escribir Enteros ⭐⭐⭐☆☆

Escribí un array de enteros en un archivo binario.

Orientación:


Ejercicio 2.04.26 - Archivo Binario - Leer Enteros ⭐⭐⭐☆☆

Leé enteros de un archivo binario y mostralos.

Orientación:


Ejercicio 2.04.27 - Archivo Binario de Estructuras ⭐⭐⭐⭐☆

Guardá y leé array de estructuras en archivo binario.

Orientación:


Ejercicio 2.04.28 - Acceso Aleatorio ⭐⭐⭐⭐☆

Implementá CRUD (Create, Read, Update, Delete) sobre archivo binario de registros.

Orientación:


Ejercicio 2.04.29 - Log de Eventos ⭐⭐⭐⭐☆

Implementá sistema de logging que agregue eventos con timestamp a un archivo.

Orientación:


Ejercicio 2.04.30 - Compresión RLE Simple ⭐⭐⭐⭐⭐

Implementá compresión Run-Length Encoding: caracteres repetidos se almacenan como <contador><carácter>.

Ejemplo: “aaabbcccc” → “3a2b4c”

Orientación:


Ejercicio 2.04.31 - Índice de Archivo ⭐⭐⭐⭐⭐

Creá un índice de palabras con sus posiciones (número de línea) en el archivo.

Orientación:


Ejercicio 2.04.32 - Diferencia Entre Archivos (diff simple) ⭐⭐⭐⭐⭐

Implementá versión simple de diff: mostrá líneas diferentes entre dos archivos.

Orientación:


Ejercicio 2.04.33 - s Adicionales ⭐⭐☆☆☆

Ejercicio 2.04.34 - Cifrado César ⭐⭐⭐⭐☆

Cifrá/descifrá un archivo usando cifrado César (rotación de N posiciones en alfabeto).

Orientación:


Ejercicio 2.04.35 - Archivo de Configuración ⭐⭐⭐⭐☆

Leé archivo de configuración estilo clave=valor.

Ejemplo:

puerto=8080
host=localhost
timeout=30

Orientación:


Ejercicio 2.04.36 - Serialización JSON Simple ⭐⭐⭐⭐⭐

Escribí y leé una estructura simple en formato JSON.

Orientación:


Notas Finales

Estas consignas cubren operaciones de archivo desde básicas hasta avanzadas, tanto en modo texto como binario, preparando para manejo robusto de persistencia de datos.