Archivos en C/C++. Hasta ahora, todos los programas han intercambiado datos únicamente con la memoria y la consola; en este capítulo aprenderemos a leer y escribir información de forma permanente mediante archivos en disco. Veremos la diferencia entre archivos de texto (legibles por humanos) y archivos binarios (datos en bruto), y utilizaremos funciones de la biblioteca estándar —como fopen
, fscanf
, fread
, fwrite
y fclose
— para manipularlos.
Veremos los modos de apertura ("r"
, "w"
, "a"
, "rb"
, etc.), cómo leer y escribir línea a línea o en bloques, y las técnicas básicas para detectar y manejar errores etc. Vamos!!!!
9.1 Archivos de texto y binarios
En C y C++, existen dos formas principales de trabajar con archivos: archivos de texto y archivos binarios. Ambos se utilizan para almacenar datos en disco, pero difieren en su estructura, forma de lectura/escritura, y propósito.
Archivos de Texto
Un archivo de texto almacena la información como una secuencia de caracteres legibles por humanos. Esto incluye números, letras, signos de puntuación y saltos de línea, codificados normalmente en ASCII o UTF-8.
Ventajas:
- Legibles y editables con cualquier editor de texto.
- Fáciles de depurar y compartir.
- Útiles para registros, configuraciones, logs, CSV, etc.
Desventajas:
- Menor eficiencia: cada número o dato se convierte en caracteres (por ejemplo, el número
12345
se guarda como cinco bytes:'1'
,'2'
,'3'
,'4'
,'5'
). - Conversión constante entre texto ↔ valores internos del programa.
Ejemplo de creación y escritura:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.txt", "w"); // Abrir archivo en modo escritura
if (archivo == NULL) {
printf("Error al abrir el archivo.\n");
return 1;
}
fprintf(archivo, "Nombre: Juan\n");
fprintf(archivo, "Edad: %d\n", 25);
fclose(archivo); // Cerrar el archivo
return 0;
}
Este archivo tendrá un contenido fácilmente legible:
Nombre: Juan
Edad: 25
Archivos Binarios
Un archivo binario almacena datos tal como están representados en memoria, sin conversión a caracteres. Es decir, los valores se guardan en formato binario bruto, lo cual es más eficiente pero no legible para humanos.
Ventajas:
- Ocupan menos espacio.
- Lectura y escritura más rápidas.
- Permiten almacenar estructuras completas o datos complejos (como imágenes, estructuras de datos, audio, video, etc.).
Desventajas:
- No son legibles sin un programa que los interprete.
- Pueden ser incompatibles entre plataformas (por ejemplo, por diferencias de tamaño de tipos de datos).
Ejemplo de escritura binaria:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.bin", "wb"); // w = write, b = binary
if (archivo == NULL) {
printf("No se pudo abrir el archivo.\n");
return 1;
}
int edad = 25;
fwrite(&edad, sizeof(int), 1, archivo); // Guarda los 4 bytes de la variable edad
fclose(archivo);
return 0;
}
Este archivo no será legible directamente en un editor de texto, pero es muy útil para almacenamiento eficiente de datos binarios.
Diferencias clave entre texto y binario
Característica | Archivos de Texto | Archivos Binarios |
---|---|---|
Legibilidad | Alta (para humanos) | Baja (requiere programa) |
Espacio en disco | Mayor | Menor |
Velocidad de acceso | Más lenta (requiere parseo) | Más rápida (acceso directo) |
Conversión de datos | Requiere conversión (ej. int ↔ string) | No necesita conversión |
Portabilidad | Alta | Media/baja (según plataforma) |
Uso típico | Logs, CSV, configs | Bases de datos, imágenes, estructuras |
9.2 Funciones básicas de archivo en C/C++
C proporciona un conjunto de funciones en la librería <stdio.h>
(Standard Input Output library) para manipular archivos de manera sencilla. En este apartado vamos a explicar las más importantes relacionadas con la gestión de archivos y cómo se usan.
📁 fopen()
La función fopen()
abre un archivo y devuelve un puntero a una variable de tipo FILE
, que se utiliza en el resto de operaciones (leer, escribir, cerrar…).
FILE *fopen(const char *nombre_archivo, const char *modo);
nombre_archivo
: nombre (y ruta opcional) del archivo.modo
: especifica cómo se abrirá el archivo.
Modos comunes:
Modo | Significado |
---|---|
"r" | Lectura (debe existir el archivo) |
"w" | Escritura (crea o sobrescribe archivo) |
"a" | Escritura al final del archivo (append) |
"rb" | Lectura binaria |
"wb" | Escritura binaria |
Ejemplo:
FILE *archivo = fopen("ejemplo.txt", "r");
if (archivo == NULL) {
printf("No se pudo abrir el archivo.\n");
}
🧾 fscanf()
y fprintf()
Estas funciones permiten leer y escribir archivos de texto, igual que scanf
y printf
lo hacen con la consola, salvo que en este caso, debemos facilitar como parámetro el puntero de tipo FILE que hemos obtenido a la hora de abrir el archivo con fopen().
✔ fprintf()
– escribir en archivos de texto
fprintf(archivo, "Nombre: %s\nEdad: %d\n", nombre, edad);
✔ fscanf()
– leer de archivos de texto
fscanf(archivo, "%s %d", nombre, &edad);
Cuidado!!!:
fscanf()
detiene la lectura cuando encuentra un espacio, salto de línea o tabulación. Para leer líneas completas se usafgets()
.
Veamos un ejemplo completo:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.txt", "w");
if (archivo == NULL) {
printf("Error al abrir archivo\n");
return 1;
}
char nombre[] = "Lucía";
int edad = 30;
fprintf(archivo, "%s %d\n", nombre, edad);
fclose(archivo);
return 0;
}
Y luego:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.txt", "r");
if (archivo == NULL) {
printf("No se pudo leer archivo\n");
return 1;
}
char nombre[50];
int edad;
fscanf(archivo, "%s %d", nombre, &edad);
printf("Nombre: %s, Edad: %d\n", nombre, edad);
fclose(archivo);
return 0;
}
fwrite()
y fread()
– Archivos Binarios
Estas funciones permiten leer y escribir datos directamente en binario, muy útiles para estructuras, arrays, imágenes, etc.
✔ fwrite()
– escribir datos binarios
Al invocar a esta función deberemos indicar la dirección de memoria donde está la información a escribir, el tamaño en bytes de la información a escribir, número de elementos y el puntero del archivo que obtuvimos con la función fopen().
fwrite(&edad, sizeof(int), 1, archivo);
- 1: número de elementos.
sizeof(int)
: tamaño de cada elemento.
✔ fread()
– leer datos binarios
Al invocar a esta función deberemos indicar la dirección de memoria donde alojar la información leída del archivo, el tamaño en bytes de la información a leer, número de elementos y el puntero del archivo que obtuvimos con la función fopen().
cCopiarEditarfread(&edad, sizeof(int), 1, archivo);
Ejemplo:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.bin", "wb");
int numero = 12345;
fwrite(&numero, sizeof(int), 1, archivo);
fclose(archivo);
return 0;
}
Y para leerlo:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.bin", "rb");
int numero;
fread(&numero, sizeof(int), 1, archivo);
printf("Número leído: %d\n", numero);
fclose(archivo);
return 0;
}
fclose()
Es fundamental cerrar el archivo una vez terminado el trabajo para liberar recursos y asegurar que los datos se escriben correctamente:
fclose(archivo);
Comprobación de errores
Es importante que siempre verifiquemos que fopen()
no devuelve NULL
, ya que eso indica que el archivo no se pudo abrir (porque el archivo no exista, porque no tengamos permisos, haya errores en disco, etc.)
if (archivo == NULL) {
perror("Error al abrir archivo"); // imprime error del sistema
return 1;
}
9.3. Lectura y escritura línea a línea en archivos de texto
En este apartado aprenderás a leer y escribir archivos de texto línea por línea, lo cual es muy útil cuando se trabaja con contenido estructurado (como listas de nombres, configuraciones, registros, etc.).
🔹 Escritura línea a línea con fprintf()
Veamos ahora como podemos hacer para escribir líneas completas en un archivo usamos la función fprintf()
. Basta con añadir un \n
al final de la cadena para insertar un salto de línea.
Ejemplo: Escribir varias líneas
#include <stdio.h>
int main() {
FILE *archivo = fopen("nombres.txt", "w");
if (archivo == NULL) {
printf("No se pudo abrir el archivo para escritura.\n");
return 1;
}
fprintf(archivo, "Lucía\n");
fprintf(archivo, "Carlos\n");
fprintf(archivo, "Marta\n");
fclose(archivo);
return 0;
}
Este código crea un archivo nombres.txt
con tres líneas, cada una con un nombre.
Lectura línea a línea con fgets()
Para leer líneas completas de un archivo usamos fgets()
. Esta función devuelve un puntero a char. o lo que es lo mismo, un vector de caracteres. A la función se le facilita el puntero a char donde almacenaremos la información (que es el mismo puntero que devolverá la función), el número de bytes que queremos leer y el puntero del archivo donde tenemos que leer).
char *fgets(char *buffer, int tamaño, FILE *archivo);
buffer
: arreglo donde se almacenará la línea leída.tamaño
: número máximo de caracteres a leer.archivo
: puntero al archivo.
@Tip: Si fgets() devuelve NULL significa que no ha podido leer nada.
Ejemplo: Leer línea por línea
#include <stdio.h>
int main() {
FILE *archivo = fopen("nombres.txt", "r");
char linea[100];
if (archivo == NULL) {
printf("No se pudo abrir el archivo para lectura.\n");
return 1;
}
while (fgets(linea, sizeof(linea), archivo) != NULL) {
printf("Línea leída: %s", linea); // No hace falta añadir \n, fgets lo incluye
}
fclose(archivo);
return 0;
}
fgets()
lee una línea del archivo (hasta que encuentra un salto de línea\n
o llega al final del archivo).- El bucle
while
continúa hasta quefgets()
devuelveNULL
, lo cual indica que se ha llegado al final del archivo o ha ocurrido un error.
Detalles importantes
- fgets conserva el salto de línea (
\n
) si existe en la línea leída. - Asegúrate siempre de definir un tamaño para el buffer suficientemente grande para las líneas esperadas.
- Ideal para trabajar con archivos tipo
.txt
o.csv
.
Combinando lectura y procesamiento
Supongamos que tienes un archivo con números (uno por línea) y deseas sumarlos:
Archivo numeros.txt
:
10
25
40
Código para sumar:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *archivo = fopen("numeros.txt", "r");
char linea[100];
int suma = 0;
if (archivo == NULL) {
printf("No se pudo abrir el archivo.\n");
return 1;
}
while (fgets(linea, sizeof(linea), archivo) != NULL) {
suma += atoi(linea); // convierte la línea a entero
}
printf("La suma total es: %d\n", suma);
fclose(archivo);
return 0;
}
9.4. Modos de apertura de archivos en C/C++
Cuando abrimos un archivo con fopen()
, indicamos no solo el nombre del archivo, sino también el modo de apertura, que define lo que queremos hacer con él (leer, escribir, añadir, en texto o binario).
FILE *fopen(const char *nombre_archivo, const char *modo);
El parámetro modo
se define con una cadena con alguno de estos valores "r"
, "w"
, "rb"
, etc.
Modo | Descripción |
---|---|
"r" | Abre un archivo para lectura. El archivo debe existir. |
"w" | Abre un archivo para escritura. Si ya existe, se borra su contenido. Si no existe, lo crea. |
"a" | Abre un archivo para añadir contenido al final (append). Si no existe, lo crea. |
"r+" | Abre un archivo para lectura y escritura. El archivo debe existir. |
"w+" | Abre un archivo para lectura y escritura, borrando su contenido si ya existe. |
"a+" | Abre un archivo para lectura y escritura, posicionando el cursor al final. Si no existe, lo crea. |
Modos en archivos binarios
Si queremos trabajar con archivos binarios, se añade una "b"
al modo:
Modo | Significado |
---|---|
"rb" | Leer un archivo binario |
"wb" | Escribir en un archivo binario (borra contenido previo) |
"ab" | Añadir contenido a un archivo binario |
"r+b" o "rb+" | Leer y escribir en binario (archivo debe existir) |
"w+b" o "wb+" | Leer y escribir, se borra contenido previo |
"a+b" o "ab+" | Leer y añadir contenido binario |
– Abrir un archivo de texto para leer:
FILE *f = fopen("archivo.txt", "r");
Si el archivo no existe, fopen()
devolverá NULL
.
– Abrir un archivo binario para escritura:
FILE *f = fopen("datos.bin", "wb");
Se crea si no existe. Si ya existe, se borra su contenido.
– Abrir un archivo de texto para añadir contenido:
FILE *f = fopen("registro.txt", "a");
Todo lo que se escriba se añadirá al final del archivo.
Comprobación al abrir archivos
Siempre es conveniente comprobar si el archivo se abrió correctamente:
FILE *f = fopen("algo.txt", "r");
if (f == NULL) {
printf("Error al abrir el archivo.\n");
}
@Tip: Cuando trabajamos con archivos binarios, no usamos funciones como fprintf()
o fscanf()
, sino que empleamos funciones como fwrite()
y fread()
para leer y escribir bloques de memoria.
9.5. Comprobación de errores al trabajar con archivos en C/C++
Ya hemos adelantado que cuando trabajamos con archivos, es fundamental comprobar si las operaciones de apertura, lectura o escritura se han realizado correctamente. Esto permite que el programa sea más robusto y evite fallos inesperados como intentar leer un archivo que no existe o escribir en uno que no se pudo abrir.
Comprobación al abrir un archivo
La función fopen()
devuelve un puntero a FILE
. Si no pudo abrirse el archivo (por ejemplo, porque no existe o no tenemos permisos), devuelve NULL
.
FILE *archivo = fopen("datos.txt", "r");
if (archivo == NULL) {
perror("Error al abrir el archivo");
return 1;
}
perror()
imprime un mensaje de error relacionado con la última operación fallida del sistema.- También puedes usar
fprintf(stderr, ...)
para enviar un mensaje de error personalizado al canal de errores.
Comprobación de lectura y escritura
Para verificar si las operaciones de lectura o escritura han funcionado correctamente, se comprueban los valores devueltos por funciones como fscanf()
, fgets()
, fread()
, fwrite()
, etc.
Ejemplo: Verificar lectura con fscanf
int numero;
if (fscanf(archivo, "%d", &numero) != 1) {
printf("Error al leer el número desde el archivo\n");
}
Ejemplo: Verificar escritura con fprintf
if (fprintf(archivo, "Hola mundo\n") < 0) {
printf("Error al escribir en el archivo\n");
}
Detección del fin del archivo
La función feof(FILE *f)
se usa para saber si se ha llegado al final del archivo. Es útil cuando leemos dentro de un bucle:
while (!feof(archivo)) {
fscanf(archivo, "%d", &num);
// ...
}
¡¡¡Importante!!! Hay que tener en cuenta que feof()
solo se activa después de intentar leer más allá del final, por lo que no siempre es la mejor forma de controlar la lectura.
Verificación de errores de I/O
ferror(FILE *f)
devuelve un valor distinto de cero si ha ocurrido un error de entrada/salida (I/O) en el archivo.
if (ferror(archivo)) {
printf("Error de entrada/salida detectado.\n");
}
Limpieza y cierre del archivo
Siempre es importante acordarse de cerrar el archivo con fclose()
después de usarlo, esto evita que se produzcan errores o que haya información en el buffer que todavía no haya volcado al archivo que se pierda ante una salida del programa.
if (fclose(archivo) != 0) {
perror("Error al cerrar el archivo");
}
Resumendo
Función | Propósito |
---|---|
fopen() | Abrir archivo |
fclose() | Cerrar archivo |
perror() | Mostrar mensaje de error del sistema |
feof() | Detectar fin de archivo |
ferror() | Detectar errores de I/O |
Recapitulando
En este capítulo hemos aprendido a manejar archivos en C y C++, mecanismo esencial para guardar y recuperar datos de forma persistente más allá del tiempo de ejecución de un programa.
Hemos visto las diferencias entre archivos de texto y archivos binarios, entendiendo cuándo es conveniente utilizar uno u otro. Nos hemos familiarizado con las funciones básicas para trabajar con archivos, como fopen
, fscanf
, fprintf
, fread
, fwrite
y fclose
, que nos permiten abrir, leer, escribir y cerrar archivos correctamente.
Aprendimos a realizar lectura y escritura línea a línea utilizando funciones como fgets()
y fputs()
, y repasamos los modos de apertura ("r"
, "w"
, "a"
, "rb"
, "wb"
, etc.), fundamentales para indicar el tipo de operación que vamos a realizar.
Finalmente, abordamos la comprobación de errores, algo crucial al trabajar con archivos: verificamos si la apertura fue exitosa, si las operaciones de lectura o escritura se realizaron correctamente, y cómo detectar el fin del archivo o errores de entrada/salida mediante funciones como feof()
, ferror()
y perror()
.
Vayamos ahora con los ejercicios prácticos.
Ejercicio 1: Contar líneas en un archivo de texto
Enunciado:
Escribe un programa en C que abra un archivo de texto llamado texto.txt
, cuente cuántas líneas contiene y muestre el resultado por pantalla. Si el archivo no existe, debe mostrar un mensaje de error.
Enunciado:
Escribe un programa en C que abra un archivo de texto llamado
texto.txt
, cuente cuántas líneas contiene y muestre el resultado por pantalla. Si el archivo no existe, debe mostrar un mensaje de error.Código.
#include <stdio.h>
int main() {
FILE *archivo = fopen("texto.txt", "r");
if (archivo == NULL) {
printf("No se pudo abrir el archivo 'texto.txt'\n");
return 1;
}
int contadorLineas = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), archivo) != NULL) {
contadorLineas++;
}
fclose(archivo);
printf("El archivo tiene %d líneas.\n", contadorLineas);
return 0;
}
Explicación:
Abrimos el archivo en modo lectura ("r"
). Usamos fgets
para leer línea a línea hasta llegar al final (NULL
). Por cada línea leída, incrementamos un contador. Al finalizar, cerramos el archivo y mostramos el total de líneas.
Ejercicio 2: Copiar contenido de un archivo de texto a otro
Enunciado:
Haz un programa que copie el contenido de un archivo origen.txt
a otro archivo llamado copia.txt
. El programa debe manejar correctamente la apertura y cierre de ambos archivos y mostrar un mensaje de éxito o error.
Enunciado:
Haz un programa que copie el contenido de un archivo
origen.txt
a otro archivo llamado copia.txt
. El programa debe manejar correctamente la apertura y cierre de ambos archivos y mostrar un mensaje de éxito o error.Codigo:
#include <stdio.h>
int main() {
FILE *archivoOrigen = fopen("origen.txt", "r");
if (archivoOrigen == NULL) {
printf("Error: no se pudo abrir el archivo origen.\n");
return 1;
}
FILE *archivoDestino = fopen("copia.txt", "w");
if (archivoDestino == NULL) {
printf("Error: no se pudo crear el archivo destino.\n");
fclose(archivoOrigen);
return 1;
}
char caracter;
while ((caracter = fgetc(archivoOrigen)) != EOF) {
fputc(caracter, archivoDestino);
}
fclose(archivoOrigen);
fclose(archivoDestino);
printf("Copia realizada con éxito.\n");
return 0;
}
Explicación:
Abrimos el archivo de origen en modo lectura y el de destino en modo escritura. Leemos carácter a carácter con fgetc
y escribimos con fputc
hasta llegar al final del archivo (EOF
). Luego cerramos ambos archivos y notificamos que la copia fue exitosa.
Ejercicio 3: Guardar números introducidos por el usuario en un archivo binario
Enunciado:
Crea un programa que pida al usuario 5 números enteros, los guarde en un archivo binario llamado numeros.bin
y luego lea ese archivo para mostrar los números almacenados.
Enunciado:
Crea un programa que pida al usuario 5 números enteros, los guarde en un archivo binario llamado
numeros.bin
y luego lea ese archivo para mostrar los números almacenados.Código:
#include <stdio.h>
int main() {
FILE *archivo = fopen("numeros.bin", "wb");
if (archivo == NULL) {
printf("No se pudo abrir el archivo para escritura.\n");
return 1;
}
int numeros[5];
printf("Introduce 5 números enteros:\n");
for (int i = 0; i < 5; i++) {
printf("Número %d: ", i + 1);
scanf("%d", &numeros[i]);
}
fwrite(numeros, sizeof(int), 5, archivo);
fclose(archivo);
// Lectura del archivo binario
archivo = fopen("numeros.bin", "rb");
if (archivo == NULL) {
printf("No se pudo abrir el archivo para lectura.\n");
return 1;
}
int numerosLeidos[5];
fread(numerosLeidos, sizeof(int), 5, archivo);
fclose(archivo);
printf("Números leídos del archivo:\n");
for (int i = 0; i < 5; i++) {
printf("%d ", numerosLeidos[i]);
}
printf("\n");
return 0;
}
Explicación:
El programa primero abre un archivo binario en modo escritura ("wb"
), pide 5 números enteros al usuario y los escribe con fwrite
. Luego cierra y vuelve a abrir el archivo en modo lectura binaria ("rb"
) para leer los números con fread
y mostrarlos. Esto ilustra la manipulación básica de archivos binarios.
Bibliografía del tutorial de C/C++.
- C/C++. Curso de programación. Autor: Miguel Angel Acera (Editorial: Anaya Multimedia)
- C/C++. Curso de programación. Autor: Francisco José Ceballos (Editorial: RA-MA)
- Un recorrido por C++. Autor Bjarne Stroustrup (Editorial: Anaya Multimedia)
- 115 Ejercicios resueltos de programación C++. Autor Jorge Fernando Betancourt e Inma Yolanda Polanco (Editorial: RA-MA)