Módulo 09 — Lectura y escritura de archivos en C

Idea central

Hasta ahora todos los datos vivían en RAM: al terminar el programa, desaparecían. Los archivos resuelven eso: permiten que un programa persista datos entre ejecuciones y comparta información con otros programas. La API de archivos de C es sencilla: abrir → operar → cerrar.

Qué aprendes

ConceptoPara qué sirve
fopen(ruta, modo)Abrir un archivo; devuelve un puntero FILE *
Modos "r", "w", "a"Leer / escribir (crea/trunca) / añadir al final
Comprobar NULLDetectar error al abrir (archivo no existe, sin permisos…)
fprintf(fp, ...)Escribir en archivo con el mismo formato que printf
fscanf(fp, ...)Leer datos formateados desde archivo
fgets(buf, n, fp)Leer una línea completa (con espacios) de forma segura
fclose(fp)Cerrar el archivo y volcar los buffers a disco

Explicación

Patrón general (siempre el mismo)

1. Declarar  FILE *fp;
2. Abrir     fp = fopen("ruta", "modo");
3. Comprobar if (fp == NULL) { /* error */ }
4. Operar    fprintf / fscanf / fgets / ...
5. Cerrar    fclose(fp);

Modos de apertura

ModoLeeEscribeCrea si no existeTrunca si existe
"r"sinonono
"w"nosisisi
"a"nosi (solo final)sino
"r+"sisinono

Sintaxis mínima

#include <stdio.h>
 
FILE *fp = fopen("datos.txt", "w");
if (fp == NULL) {
    printf("Error al abrir el archivo\n");
    return 1;          // salir con codigo de error
}
 
fprintf(fp, "Hola, archivo!\n");
fclose(fp);

Leer líneas con fgets

char linea[256];
FILE *fp = fopen("datos.txt", "r");
if (fp == NULL) return 1;
 
while (fgets(linea, sizeof(linea), fp) != NULL) {
    printf("%s", linea);   // linea ya incluye '\n'
}
fclose(fp);

fgets devuelve NULL al llegar al final del archivo (EOF), lo que hace el bucle while natural.

Leer números con fscanf

int n;
while (fscanf(fp, "%d", &n) == 1) {   // == 1: leyo un entero correctamente
    printf("%d\n", n);
}

Worked example

Problema: Pedir al usuario 3 nombres, guardarlos en nombres.txt, volver a abrirlo y mostrarlos numerados.

#include <stdio.h>
#include <string.h>
 
int main(void) {
    // --- PASO 1: escribir 3 nombres ---
    FILE *fw = fopen("nombres.txt", "w");
    if (fw == NULL) {
        printf("No se pudo crear el archivo\n");
        return 1;
    }
 
    char nombre[64];
    for (int i = 0; i < 3; i++) {
        printf("Nombre %d: ", i + 1);
        scanf("%63s", nombre);
        fprintf(fw, "%s\n", nombre);   // una linea por nombre
    }
    fclose(fw);   // SIEMPRE cerrar antes de volver a abrir
 
    // --- PASO 2: leer y mostrar numerados ---
    FILE *fr = fopen("nombres.txt", "r");
    if (fr == NULL) {
        printf("No se pudo leer el archivo\n");
        return 1;
    }
 
    printf("\n--- Contenido del archivo ---\n");
    int linea = 1;
    char buf[64];
    while (fgets(buf, sizeof(buf), fr) != NULL) {
        // fgets conserva el '\n'; quitarlo para mostrar limpio
        buf[strcspn(buf, "\n")] = '\0';
        printf("%d. %s\n", linea++, buf);
    }
    fclose(fr);
    return 0;
}

Por qué funciona paso a paso:

  1. Abrimos con "w" → crea/trunca nombres.txt.
  2. fprintf(fw, "%s\n", nombre) escribe cada nombre seguido de salto de línea.
  3. fclose(fw) vuelca los buffers; sin esto el archivo puede quedar vacío.
  4. Abrimos con "r" → el archivo ya tiene datos.
  5. fgets lee hasta \n o sizeof(buf)-1 caracteres; al llegar a EOF devuelve NULL y el while termina.
  6. strcspn(buf, "\n") devuelve el índice del primer \n; ponerlo a '\0' lo elimina.

Salida ejemplo:

Nombre 1: Ana
Nombre 2: Bruno
Nombre 3: Carla

--- Contenido del archivo ---
1. Ana
2. Bruno
3. Carla

Errores típicos en C

#ErrorPor qué falla
1No comprobar fopen == NULLEl programa peta con segfault si el archivo no existe
2Olvidar fcloseLos datos pueden no llegar a disco (el buffer se descarta)
3Usar "w" cuando quieres añadirModo "w" trunca: pierdes todo el contenido previo
4fscanf sin & en variables escalaresLee a dirección inválida → comportamiento indefinido
5fgets con buffer demasiado pequeñoTrunca la línea; el \n queda en el stream para la siguiente lectura

Ejercicios

Practica lo de este módulo. Cada enlace abre el ejercicio con su enunciado, diagrama de flujo, explicación y el código listo para copiar.

Conexiones

  • 00_README
  • Linux
  • 08-structs — módulo anterior: structs que ahora podrás persistir en disco
  • (Módulo 10 por definir) — siguiente paso