Ficheros
Introducción
En P1 (C) trabajabas con FILE* y funciones como:
fopen,fclosefprintf,fscanf(texto)fwrite,fread(binario)fgets,fputs,fgetc(texto por líneas / caracteres)
En P2 (C++) no profundizamos en el uso de ficheros, pero podemos utilizar lo siguiente:
std::ifstream,std::ofstream,std::fstream(texto)read/writeen modo binariostd::stringystd::getlinepara líneas
En este tema usamos 3 ejemplos representativos (texto+binario, lectura+media, copia binaria).
1) Guardar una estructura en binario y en texto
Guardamos un TPersona en:
persona.dat(binario)persona.txt(texto)
P1 — C
#include <stdio.h>#include <string.h>
typedef struct { char nombre[20]; int edad;} TPersona;
int main() { TPersona alumno = {"Ana", 22};
// Guardar en binario FILE *fb = fopen("persona.dat", "wb"); if (fb != NULL) { fwrite(&alumno, sizeof(TPersona), 1, fb); fclose(fb); }
// Guardar en texto FILE *ft = fopen("persona.txt", "w"); if (ft != NULL) { fprintf(ft, "%s %d\n", alumno.nombre, alumno.edad); fclose(ft); }
return 0;}P2 — C++
#include <fstream>#include <iostream>#include <cstring>
struct Persona { char nombre[20]; int edad;};
int main() { Persona alumno{}; std::strncpy(alumno.nombre, "Ana", sizeof(alumno.nombre) - 1); alumno.edad = 22;
// Guardar en binario { std::ofstream fb("persona.dat", std::ios::binary); if (fb) { fb.write(reinterpret_cast<const char*>(&alumno), sizeof(Persona)); } }
// Guardar en texto { std::ofstream ft("persona.txt"); if (ft) { ft << alumno.nombre << " " << alumno.edad << "\n"; } }
return 0;}Nota: para binario, el struct tiene char[] (datos “planos”). Si usáramos std::string, no podríamos volcarlo tal cual con write sin definir un formato ya que su tamaño sería variable. Sin embargo, se pueden utilizar strings con ficheros de texto (no binarios).
2) Leer enteros de un fichero de texto y calcular su media
Considera que tenemos un fichero de texto datos.txt que contiene enteros separados por espacios o saltos de línea.
P1 — C
#include <stdio.h>
int main() { FILE *f; int x; int contador = 0; int suma = 0; double media;
f = fopen("datos.txt", "r"); if (f == NULL) { printf("No se ha podido abrir el fichero.\n"); } else { while (fscanf(f, "%d", &x) != EOF) { suma += x; contador++; } fclose(f);
if (contador > 0) { media = (double)suma / contador; printf("Media: %.2f\n", media); } else { printf("El fichero no contiene enteros.\n"); } }
return 0;}P2 — C++
#include <fstream>#include <iostream>#include <iomanip>
int main() { std::ifstream f("datos.txt"); if (!f) { std::cout << "No se ha podido abrir el fichero.\n"; return 0; }
long long suma = 0; int contador = 0; int x;
while (f >> x) { // lee enteros separados por espacios/saltos suma += x; contador++; }
if (contador > 0) { double media = static_cast<double>(suma) / contador; std::cout << std::fixed << std::setprecision(2) << "Media: " << media << "\n"; } else { std::cout << "El fichero no contiene enteros.\n"; }
return 0;}3) Copiar un fichero binario a otro (buffer + argumentos)
En este ejercicio, se considera que el usuario pasa dos argumentos al programa en el momento de ejecutarlo: origen y destino.
P1 — C
#include <stdio.h>#define TAM 2048
int main(int argc, char **argv) { FILE *fe = NULL; FILE *fs = NULL; char buffer[TAM]; size_t leidos;
if (argc != 3) { printf("Uso: programa origen destino\n"); } else {
fe = fopen(argv[1], "rb"); if (fe == NULL) { printf("Error al abrir %s\n", argv[1]); } else {
fs = fopen(argv[2], "wb"); if (fs == NULL) { printf("Error al crear %s\n", argv[2]); } else {
while ((leidos = fread(buffer, 1, TAM, fe)) > 0) { fwrite(buffer, 1, leidos, fs); }
fclose(fs); }
fclose(fe); } }
return 0;}P2 — C++
#include <fstream>#include <iostream>
int main(int argc, char** argv) { if (argc != 3) { std::cout << "Uso: programa origen destino\n"; return 0; }
std::ifstream fe(argv[1], std::ios::binary); if (!fe) { std::cout << "Error al abrir " << argv[1] << "\n"; return 0; }
std::ofstream fs(argv[2], std::ios::binary); if (!fs) { std::cout << "Error al crear " << argv[2] << "\n"; return 0; }
char buffer[2048]; while (fe) { fe.read(buffer, sizeof(buffer)); std::streamsize leidos = fe.gcount(); // bytes realmente leídos if (leidos > 0) { fs.write(buffer, leidos); } }
return 0;}Recordatorio importante
-
Texto: cómodo de inspeccionar, pero ocupa más y requiere conversión de datos a secuencias de caracteres. Esto no lo haces explícitamente en C++.
-
Binario: compacto y rápido, pero depende del formato y no es legible. No se puede interpretar con un editor de texto, pero es más eficiente.
-
En binario, define bien el formato si hay arrays variables o std::string.
-
Independientemente del tipo de fichero, siempre se debe comprobar que se ha podido abrir el fichero antes de leer o escribir en él.