Manejo de archivos en C: Dominando E/S con fopen, fprintf, fread y fseek
Manejo de archivos en C
Este tutorial le guía a través de E/S de archivos en C, cubriendo operaciones estándar y binarias con ejemplos claros y prácticos.
Un archivo es un contenedor lógico en el almacenamiento de una computadora que contiene datos para uso a largo plazo.
¿Por qué usar archivos?
- Los datos persisten después de que un programa termina, evitando pérdida de información.
- Grandes conjuntos de datos pueden almacenarse una vez y accederse rápidamente mediante unos pocos comandos C.
- Los archivos pueden moverse entre computadoras sin modificación.
Tipos de archivos
En C, encontrará dos tipos principales de archivos:
- Archivos de texto
- Archivos binarios
Archivos de texto
Archivos de texto plano (ej. .txt) son editables con cualquier editor de texto. Son fáciles de leer, mantener y transferir pero ocupan más espacio y ofrecen seguridad mínima.
Archivos binarios
Archivos binarios (comúnmente .bin) almacenan datos como bytes crudos (0s y 1s). Son compactos, no legibles por humanos, y proporcionan mejor integridad y seguridad de datos.
Operaciones principales de archivos
Independientemente del tipo, el manejo de archivos en C gira en torno a cuatro operaciones:
- Crear un nuevo archivo
- Abrir un archivo existente
- Cerrar un archivo
- Leer desde o escribir en un archivo
Preparación de un puntero a archivo
Todas las operaciones de archivo requieren un puntero FILE * para referenciar el archivo abierto:
FILE *fptr;
Apertura de archivos: Creación y edición
La función fopen() (declarada en stdio.h) abre un archivo y devuelve un puntero FILE *. Su sintaxis es:
fptr = fopen("nombre_archivo", "modo");
Ejemplos de uso:
fopen("E:\\cprogram\\newprogram.txt", "w");
fopen("E:\\cprogram\\oldprogram.bin", "rb");
Explicación:
newprogram.txtse crea (si no existe) y abre para escritura en modo'w', que sobrescribe cualquier contenido existente.oldprogram.binse abre para lectura binaria únicamente en modo'rb'; intentar escribir fallará.
| Modo | Significado | Comportamiento si el archivo no existe |
|---|---|---|
r | Abrir para lectura | Devuelve NULL |
rb | Abrir para lectura binaria | Devuelve NULL |
w | Abrir para escritura (sobrescribir) | Crea archivo si no existe |
wb | Abrir para escritura binaria (sobrescribir) | Crea archivo si no existe |
a | Abrir para añadir | Crea archivo si no existe |
ab | Abrir para añadir binario | Crea archivo si no existe |
r+ | Lectura y escritura | Devuelve NULL |
rb+ | Lectura y escritura en binario | Devuelve NULL |
w+ | Lectura y escritura (sobrescribir) | Crea archivo si no existe |
wb+ | Lectura y escritura en binario (sobrescribir) | Crea archivo si no existe |
a+ | Lectura y añadir | Crea archivo si no existe |
ab+ | Lectura y añadir binario | Crea archivo si no existe |
Cierre de un archivo
Después de todas las operaciones E/S, siempre cierre el archivo con fclose() para liberar recursos y vaciar búferes:
fclose(fptr);
E/S de archivos de texto
Los archivos de texto se manejan con fprintf() y fscanf(), los homólogos basados en archivo de printf() y scanf(). Requieren un puntero FILE * como primer argumento.
Ejemplo 1: Escribir en un archivo de texto
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
// Ajuste la ruta para su SO
fptr = fopen("C:\\program.txt", "w");
if (fptr == NULL) {
printf("Error al abrir archivo\n");
exit(EXIT_FAILURE);
}
printf("Introduzca un número: ");
scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
Este programa captura un entero del usuario y lo escribe en program.txt.
Ejemplo 2: Leer desde un archivo de texto
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
fptr = fopen("C:\\program.txt", "r");
if (fptr == NULL) {
printf("Error al abrir archivo\n");
exit(EXIT_FAILURE);
}
fscanf(fptr, "%d", &num);
printf("Valor leído: %d\n", num);
fclose(fptr);
return 0;
}
Ejecutar esto después del primer ejemplo mostrará el entero almacenado.
Utilidades adicionales como fgetc() y fputc() siguen el mismo patrón.
E/S de archivos binarios
Los archivos binarios se manipulan con fwrite() para escritura y fread() para lectura. Ambas funciones aceptan cuatro argumentos: puntero a datos, tamaño de cada elemento, número de elementos y puntero FILE *.
Escritura en un archivo binario
fwrite(direccionDatos, tamañoDato, númeroDatos, punteroArchivo);
Ejemplo 3: Escribir en archivo binario usando fwrite()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "wb");
if (fptr == NULL) {
printf("Error al abrir archivo\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
num.n1 = i;
num.n2 = 5 * i;
num.n3 = 5 * i + 1;
fwrite(&num, sizeof(struct threeNum), 1, fptr);
}
fclose(fptr);
return 0;
}
Lectura desde un archivo binario
La firma correspondiente de fread() refleja fwrite():
fread(direccionDatos, tamañoDato, númeroDatos, punteroArchivo);
Ejemplo 4: Leer desde archivo binario usando fread()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error al abrir archivo\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
}
fclose(fptr);
return 0;
}
Este programa reproduce los datos escritos en el Ejemplo 3.
Acceso aleatorio con fseek()
Cuando un archivo contiene muchos registros, recorrer secuencialmente hasta una entrada específica puede ser ineficiente. fseek() mueve el puntero de archivo a una posición arbitraria, permitiendo acceso directo.
Sintaxis
fseek(FILE *stream, long int offset, int whence);
stream: puntero devuelto porfopen().offset: número de bytes a mover.whence: punto de partida –SEEK_SET,SEEK_CURoSEEK_END.
| Constante | Significado |
|---|---|
SEEK_SET | El offset comienza desde el inicio del archivo. |
SEEK_CUR | El offset comienza desde la posición actual del cursor. |
SEEK_END | El offset comienza desde el final del archivo. |
Ejemplo 5: Lectura en orden inverso con fseek()
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("Error al abrir archivo\n");
exit(EXIT_FAILURE);
}
// Mover al último registro
fseek(fptr, -sizeof(struct threeNum), SEEK_END);
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
// Retroceder dos registros (actual + uno más) para leer la entrada anterior
fseek(fptr, -2 * sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);
return 0;
}
Este fragmento demuestra cómo recorrer un archivo binario en reversa, comenzando desde el último registro.
Lenguaje C
- Entendiendo los archivos STL: La columna vertebral de la impresión 3D
- Dominando E/S de archivos en C: Crear, abrir y gestionar archivos
- Entendiendo los Archivos de Cabecera en C: Tipos, Uso y Buenas Prácticas
- Manejo de Errores en C: Mejores Prácticas y Técnicas
- Dominando Entrada/Salida de Archivos en C++: Lectura y Escritura con fstream
- Dominar el manejo de señales en C++: Gestión segura de interrupciones y terminación limpia del programa
- Manejo de excepciones en C#: Estrategias y mejores prácticas
- Entrada/Salida de archivos en C#: Lectura, escritura y gestión de streams
- Dominando la E/S de Archivos en Verilog: Abrir, Leer, Escribir y Cerrar
- Entrada/Salida de Archivos en Python: Domina las Operaciones I/O
- Dominando las operaciones de archivos en Java con java.io: creación, lectura, escritura y eliminación