Manejo de Archivos en C: Guía Técnica de Lectura, Escritura y Posicionamiento

Conceptos Fundamentales de la Gestión de Archivos

Tipos de Archivos

En el lenguaje C, los archivos se clasifican principalmente en archivos de programa y archivos de datos. Los archivos de datos, que son el foco de las operaciones de entrada y salida (E/S), se dividen en dos categorías: texto y binarios. Los archivos de texto almacenan información como secuencias de caracteres legibles, lo que facilita su enspección y edición manual. Por el contrario, los archivos binarios guardan la información en el formato de memoria nativo de la máquina, otpimizando el rendimiento y el espacio al tratar con estructuras de datos complejas.

Punteros a Archivos

La interacción con el sistema de archivos se realiza a través de la estructura FILE. Un puntero de tipo FILE * actúa como el identificador y canal de comunicación entre el programa y el recurso en disco, manteniendo el estado del flujo y la posición actual de lectura o escritura.

Apertura y Cierre de Archivos

La función fopen inicializa el flujo de datos. Si la operación es exitosa, devuelve un puntero válido; en caso de fallo (por ejemplo, permisos insuficientes o ruta inexistente), retorna NULL. Es una práctica obligatoria validar este retorno para garantizar la robustez del software. Para liberar los recursos asociados, se debe invocar fclose y, opcionalmente, anular el puntero para evitar referencias colgantes.

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *archivo = fopen("registro.log", "a");
    if (!archivo) {
        perror("Error al abrir el archivo");
        return EXIT_FAILURE;
    }
    
    // Operaciones de E/S
    
    fclose(archivo);
    archivo = NULL;
    return EXIT_SUCCESS;
}

Operaciones Secuenciales de Lectura y Escritura

Manipulación de Caracteres

Las funciones fputc y fgetc permiten escribir y leer flujos de datos byte a byte. A continuación, se muestra la generación de un archivo con dígitos numéricos y su posterior lectura hasta alcanzar el indicador de fin de archivo (EOF).

// Escritura de caracteres
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("digitos.txt", "w");
    if (!flujo) return EXIT_FAILURE;
    
    for (char c = '0'; c <= '9'; c++) {
        fputc(c, flujo);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}
// Lectura de caracteres
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("digitos.txt", "r");
    if (!flujo) return EXIT_FAILURE;
    
    int caracter;
    while ((caracter = fgetc(flujo)) != EOF) {
        putchar(caracter);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Manipulación de Líneas de Texto

Para procesar bloques de texto delimitados por saltos de línea, se utilizan fputs y fgets. Esta última función asegura que no se exceda el tamaño del búfer de destino, previniendo desbordamientos de memoria.

// Escritura de líneas
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("config.ini", "w");
    if (!flujo) return EXIT_FAILURE;
    
    const char *lineas[] = {"[General]\n", "version=1.0\n", "debug=false\n"};
    for (int i = 0; i < 3; i++) {
        fputs(lineas[i], flujo);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}
// Lectura de líneas
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("config.ini", "r");
    if (!flujo) return EXIT_FAILURE;
    
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), flujo)) {
        printf("%s", buffer);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Entrada y Salida Formateada

Las funciones fprintf y fscanf operan de manera análoga a printf y scanf, pero redirigen el flujo hacia un archivo. Son ideales para persistir o recuperar datos estructurados en formato de texto plano.

// Escritura formateada
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char departamento[30];
    double salario;
} Empleado;

int main() {
    FILE *flujo = fopen("empleados.txt", "w");
    if (!flujo) return EXIT_FAILURE;
    
    Empleado emp = {"Ingenieria", 75000.50};
    fprintf(flujo, "Dept: %s | Salario: %.2f\n", emp.departamento, emp.salario);
    
    fclose(flujo);
    return EXIT_SUCCESS;
}
// Lectura formateada
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    char departamento[30];
    double salario;
} Empleado;

int main() {
    FILE *flujo = fopen("empleados.txt", "r");
    if (!flujo) return EXIT_FAILURE;
    
    Empleado emp;
    if (fscanf(flujo, "Dept: %s | Salario: %lf", emp.departamento, &emp.salario) == 2) {
        printf("Leido -> Departamento: %s, Salario: %.2f\n", emp.departamento, emp.salario);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Lectura y Escritura Binaria

Cuando se trabaja con estructuras complejas o grandes volúmenes de datos, fwrite y fread permiten volcar o cargar bloques de memoria directamente, sin overhead de conversión de texto.

// Escritura binaria
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    float temperatura;
    int humedad;
} DatosSensor;

int main() {
    FILE *flujo = fopen("sensores.dat", "wb");
    if (!flujo) return EXIT_FAILURE;
    
    DatosSensor lectura = {23.5f, 65};
    fwrite(&lectura, sizeof(DatosSensor), 1, flujo);
    
    fclose(flujo);
    return EXIT_SUCCESS;
}
// Lectura binaria
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    float temperatura;
    int humedad;
} DatosSensor;

int main() {
    FILE *flujo = fopen("sensores.dat", "rb");
    if (!flujo) return EXIT_FAILURE;
    
    DatosSensor lectura;
    if (fread(&lectura, sizeof(DatosSensor), 1, flujo) == 1) {
        printf("Sensor -> Temp: %.1f C, Humedad: %d%%\n", lectura.temperatura, lectura.humedad);
    }
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Acceso Aleatorio a Archivos

Función fseek

La función fseek permite reposicionar el indicador de posición interna del flujo. Acepta un desplazamiento (offset) y un punto de referencia (SEEK_SET, SEEK_CUR, SEEK_END).

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("datos.bin", "rb+");
    if (!flujo) return EXIT_FAILURE;
    
    // Mover el puntero 5 bytes antes del final del archivo
    fseek(flujo, -5L, SEEK_END);
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Función rewind

Para reinciiar el indicador de posición al inicio absoluto del archivo de manera rápida y sin evaluar errores de desplazamiento, se emplea rewind.

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("datos.txt", "r");
    if (!flujo) return EXIT_FAILURE;
    
    fgetc(flujo); // Avanzar un byte
    
    // Reiniciar al inicio
    rewind(flujo);
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Función ftell

La función ftell consulta la posición actual del indicador de archivo en relación con el inicio del mismo, devolviendo un valor de tipo long.

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *flujo = fopen("datos.txt", "r");
    if (!flujo) return EXIT_FAILURE;
    
    fgetc(flujo);
    fgetc(flujo);
    
    long posicion = ftell(flujo);
    printf("Posicion actual del puntero: %ld\n", posicion);
    
    fclose(flujo);
    return EXIT_SUCCESS;
}

Etiquetas: C stdio.h file-I/O fopen fread

Publicado el 7-15 05:21