C
Tutorial C: E/S binaria y formateo
C: Aprende a manipular archivos binarios usando fread() y fwrite() para una eficiente gestión de datos.
Aprende C y certifícateLectura y escritura en formato binario: fread()
, fwrite()
La lectura y escritura en formato binario permiten manejar datos de forma más eficiente y exacta en C. A diferencia del tratamiento de archivos de texto, los archivos binarios almacenan los datos en el mismo formato que se utilizan en memoria, lo que evita conversiones y posibles pérdidas de información.
Para manejar archivos binarios, se utilizan las funciones fread()
y fwrite()
. Estas funciones facilitan la transferencia de bloques de datos entre la memoria y el archivo.
Sintaxis básica de fread()
y fwrite()
:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
ptr
: Puntero al bloque de memoria donde se almacenarán (o tomarán) los datos.size
: Tamaño en bytes de cada elemento a leer o escribir.count
: Número de elementos que se leerán o escribirán.stream
: Puntero al objetoFILE
que representa el archivo.
Ejemplo de escritura en un archivo binario:
Supongamos que tenemos una estructura Persona
y deseamos guardar una lista de personas en un archivo binario:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char nombre[50];
float salario;
} Persona;
int main() {
FILE *archivo = fopen("personas.dat", "wb");
if (archivo == NULL) {
perror("Error al abrir el archivo");
return EXIT_FAILURE;
}
Persona personas[2];
personas[0].id = 1;
strcpy(personas[0].nombre, "Ana García");
personas[0].salario = 3000.50;
personas[1].id = 2;
strcpy(personas[1].nombre, "Luis Pérez");
personas[1].salario = 4000.75;
size_t elementosEscritos = fwrite(personas, sizeof(Persona), 2, archivo);
if (elementosEscritos < 2) {
perror("Error al escribir en el archivo");
}
fclose(archivo);
return EXIT_SUCCESS;
}
En este ejemplo:
- Se crea un arreglo de dos estructuras
Persona
. - Se abre (o crea) el archivo
personas.dat
en modo binario de escritura ("wb"
). - Se utiliza
fwrite()
para escribir las dos estructuras en el archivo de una sola vez. - Se verifica si se ha escrito el número esperado de elementos.
Ejemplo de lectura desde un archivo binario:
Ahora, leeremos las personas desde el archivo binario que acabamos de crear:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int id;
char nombre[50];
float salario;
} Persona;
int main()
{
FILE *archivo = fopen("personas.dat", "wb");
if (archivo == NULL)
{
perror("Error al abrir el archivo");
return EXIT_FAILURE;
}
int arr_size = 1;
int index = 0;
Persona *personas = malloc(sizeof(Persona) * arr_size);
if (personas == NULL)
{
printf("Error al reservar memoria");
return EXIT_FAILURE;
}
while (1)
{
char entrada[50];
printf("Ingrese el nombre (escriba 'exit' para salir): ");
scanf("%s", entrada);
if (strcmp(entrada, "exit") == 0)
{
free(personas);
break;
}
strcpy(personas[index].nombre, entrada);
printf("Ingrese el salario: ");
scanf("%f", &personas[index].salario);
// Tamaño del array dinámico
arr_size++;
index++;
Persona *nueva_personas = (Persona *)realloc(personas, arr_size * sizeof(Persona));
if (nueva_personas == NULL)
{
printf("Error al reservar memoria");
return EXIT_FAILURE;
}
personas = nueva_personas;
}
size_t elementosEscritos = fwrite(personas, sizeof(Persona), arr_size, archivo);
if (elementosEscritos < arr_size)
{
perror("Error al escribir en el archivo");
}
fclose(archivo);
return EXIT_SUCCESS;
}
En este código:
- Se abre el archivo
personas.dat
en modo binario de escritura ("wb"
). - Se solicita al usuario ingresar datos de varias personas, almacenándolos en un array dinámico.
- Se utiliza
realloc
para redimensionar el array cuando se agregan nuevos elementos. - Los datos ingresados se escriben en el archivo usando
fwrite
. - Se verifica si la escritura se realizó correctamente.
- Finalmente, se liberan los recursos y se cierra el archivo.
Consideraciones importantes al usar fread()
y fwrite()
:
- Consistencia en las estructuras: Asegúrate de que la definición de la estructura sea la misma al escribir y al leer el archivo. Cambios en la estructura pueden causar incompatibilidades.
- Endianness: La representación de bytes puede variar entre diferentes arquitecturas (little-endian vs big-endian). Esto puede causar problemas al compartir archivos binarios entre sistemas diferentes.
- Portabilidad: Los archivos binarios son menos portátiles que los archivos de texto. Si necesitas compartir datos entre distintas plataformas, considera utilizar formatos estándar o convertir los datos a texto.
Lectura y escritura de datos individuales:
También es posible leer y escribir datos individuales o bloques pequeños:
int numero = 28;
fwrite(&numero, sizeof(int), 1, archivo);
Bucles para procesar archivos grandes:
Cuando se trabaja con archivos grandes, es común leer o escribir en bloques para optimizar el rendimiento:
char buffer[1024];
size_t bytesLeidos;
while ((bytesLeidos = fread(buffer, 1, sizeof(buffer), archivo)) > 0) {
// Procesar datos del buffer
}
En este fragmento:
- Buffering: Se utiliza un buffer para almacenar temporalmente los datos leídos.
- Eficiencia: Leer en bloques grandes reduce el número de operaciones de E/S, mejorando la eficiencia.
Manejo de errores y final de archivo:
- Comprobar valores de retorno: Siempre verifica el valor devuelto por
fread()
yfwrite()
para asegurarte de que la operación se realizó correctamente. - Funciones auxiliares: Utiliza
feof()
para detectar el final del archivo yferror()
para identificar errores en las operaciones de E/S.
if (feof(archivo)) {
printf("Se alcanzó el final del archivo.\n");
} else if (ferror(archivo)) {
perror("Error durante la lectura del archivo");
}
Manipulación de archivos binarios vs. texto
La manipulación de archivos en C puede llevarse a cabo en dos formatos principales: binario y texto. Aunque ambos tipos de archivos almacenan datos, la forma en que se representan y se manejan difiere significativamente.
En los archivos de texto, los datos se almacenan como una secuencia de caracteres legibles por humanos. Estos archivos utilizan convenciones de codificación, como ASCII o UTF-8, para representar caracteres alfanuméricos. Además, los archivos de texto suelen interpretar caracteres especiales, como el salto de línea \n
o el fin de archivo EOF, lo que puede afectar la forma en que se procesan los datos.
Por otro lado, los archivos binarios almacenan datos en el mismo formato en que se representan en memoria. Esto significa que los datos se guardan como secuencias de bytes sin ninguna conversión o interpretación adicional. Los archivos binarios son ideales para guardar estructuras complejas o datos que no necesitan ser legibles por humanos, ya que preservan la integridad de los valores almacenados.
Modos de apertura con fopen()
Al abrir un archivo con la función fopen()
, es crucial especificar el modo correcto para evitar comportamientos inesperados. Los modos difieren entre archivos de texto y binarios:
Tipo de Archivo | Operación | Modo |
---|---|---|
Archivos de texto | Lectura | r |
Escritura | w |
|
Añadir al final | a |
|
Archivos binarios | Lectura | rb |
Escritura | wb |
|
Añadir al final | ab |
El sufijo "b"
en los modos indica que el archivo se tratará como binario. Aunque en sistemas UNIX no hay diferencia notable entre modos binarios y de texto, en sistemas Windows es fundamental utilizar el modo correcto debido al manejo distinto de caracteres como el retorno de carro y el salto de línea.
Diferencias en la lectura y escritura
Cuando se trabaja con archivos de texto, se suelen utilizar funciones como fprintf()
, fscanf()
, fgets()
y fputs()
. Estas funciones realizan conversiones entre tipos de datos internos y sus representaciones en cadena. Por ejemplo, fprintf()
convierte un entero en su representación de caracteres antes de escribirlo en el archivo.
Ejemplo de escritura en un archivo de texto:
FILE *archivo = fopen("datos.txt", "w");
if (archivo != NULL) {
int numero = 42;
fprintf(archivo, "%d\n", numero);
fclose(archivo);
}
En contraste, para archivos binarios, se utilizan fread()
y fwrite()
, que leen y escriben datos en forma de bloques de bytes sin realizar conversiones. Esto preserva la exactitud y eficiencia al manipular datos binarios.
Ejemplo de escritura en un archivo binario:
FILE *archivo = fopen("datos.bin", "wb");
if (archivo != NULL) {
int numero = 42;
fwrite(&numero, sizeof(int), 1, archivo);
fclose(archivo);
}
Consideraciones sobre portabilidad y compatibilidad
Al usar archivos binarios, hay que tener en cuenta factores como la endianess y el tamaño de los tipos de datos, que pueden variar entre diferentes arquitecturas y compiladores. Esto puede provocar que un archivo binario escrito en una plataforma no sea legible en otra.
Por ejemplo, un entero de 32 bits almacenado en un sistema little-endian puede no interpretarse correctamente en un sistema big-endian. Para mejorar la portabilidad, es recomendable definir formatos consistentes o utilizar funciones de conversión cuando sea necesario.
En cambio, los archivos de texto son más portátiles entre diferentes sistemas, ya que se basan en estándares de codificación de caracteres. Sin embargo, hay que tener cuidado con las convenciones de fin de línea, especialmente al mover archivos entre sistemas Unix/Linux (que usan \n
) y Windows (que usan \r\n
).
Uso de funciones específicas
Las funciones de E/S estándares en C están diseñadas para un tipo específico de archivo:
Funciones para archivos de texto:
fprintf()
,fscanf()
: Para leer y escribir con formato.fgets()
,fputs()
: Para manejar cadenas de caracteres.fgetc()
,fputc()
: Para leer y escribir caracteres individuales.
Funciones para archivos binarios:
fread()
,fwrite()
: Para leer y escribir bloques de datos.fseek()
,ftell()
: Para mover y obtener la posición del puntero en el archivo.
Ejemplo comparativo
Supongamos que deseamos guardar un arreglo de números enteros en un archivo. A continuación, se muestran ejemplos de cómo hacerlo en ambos formatos.
Escritura en un archivo de texto:
int numeros[] = {10, 20, 30, 40, 50};
FILE *archivoTexto = fopen("numeros.txt", "w");
if (archivoTexto != NULL) {
for (int i = 0; i < 5; i++) {
fprintf(archivoTexto, "%d\n", numeros[i]);
}
fclose(archivoTexto);
}
Escritura en un archivo binario:
int numeros[] = {10, 20, 30, 40, 50};
FILE *archivoBinario = fopen("numeros.bin", "wb");
if (archivoBinario != NULL) {
fwrite(numeros, sizeof(int), 5, archivoBinario);
fclose(archivoBinario);
}
En la versión de texto, los números se convierten a su representación de caracteres y se separan por saltos de línea. En la versión binaria, el arreglo completo se escribe tal cual está en memoria, sin conversiones.
Lectura y posibles errores comunes
Al leer archivos de texto, es importante manejar adecuadamente las conversiones y estar atento a posibles errores de formato. Por ejemplo, si se espera un entero pero el archivo contiene texto no numérico, fscanf()
puede fallar o comportarse de manera inesperada.
En la lectura de archivos binarios, es crucial asegurarse de que el tamaño y la estructura de los datos sean consistentes con lo que se espera. Un error común es no tener en cuenta el tamaño de los tipos de datos o cambios en la definición de estructuras, lo que puede llevar a lecturas incorrectas o corrupción de datos.
Cuándo elegir cada formato
- Archivos de texto:
- Cuando se necesita que los datos sean legibles y editables por humanos.
- Para facilitar la depuración y modificación manual.
- Cuando la portabilidad entre diferentes sistemas es una prioridad.
- Archivos binarios:
- Para almacenar grandes cantidades de datos de manera eficiente.
- Cuando se requiere un acceso rápido y directo a estructuras complejas.
- Cuando la precisión y exactitud de los datos son críticas, sin pérdidas por conversiones.
Impacto en el tamaño del archivo y rendimiento
Los archivos binarios suelen ser más compactos que los de texto, ya que no incluyen caracteres adicionales para representar los datos. Además, las operaciones de lectura y escritura pueden ser más rápidas debido a la ausencia de conversiones.
Sin embargo, los archivos de texto ofrecen mayor flexibilidad y son más fáciles de inspeccionar y modificar sin herramientas especializadas.
Serialización simple de estructuras
La serialización es el proceso de convertir una estructura de datos en una secuencia de bytes para almacenarla o transmitirla y posteriormente reconstruirla en su forma original. En C, es posible serializar estructuras simples utilizando funciones de E/S binaria, lo que facilita el almacenamiento persistente y la transferencia de datos.
Para llevar a cabo una serialización simple de estructuras, se emplean las funciones fwrite()
y fread()
. Estas funciones permiten escribir y leer bloques de memoria que representan las estructuras, preservando su integridad y formato interno.
Consideraciones al serializar estructuras:
Alineación y relleno: Las estructuras pueden contener bytes de relleno debido a la alineación de memoria, lo que afecta su tamaño. Es fundamental conocer el tamaño exacto de la estructura con sizeof()
para evitar inconsistencias al leer y escribir.
Portabilidad: La endianness (orden de bytes) y el tamaño de los tipos de datos pueden variar entre arquitecturas y compiladores. Esto puede causar problemas al deserializar estructuras en sistemas diferentes al original.
A continuación, se presenta un ejemplo de cómo serializar y deserializar una estructura simple en un archivo binario.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int id;
char nombre[50];
float salario;
} Empleado;
void guardarEmpleados(const char *nombreArchivo, Empleado *empleados, size_t cantidad) {
FILE *archivo = fopen(nombreArchivo, "wb");
if (archivo == NULL) {
perror("Error al abrir el archivo para escritura");
exit(EXIT_FAILURE);
}
size_t elementosEscritos = fwrite(empleados, sizeof(Empleado), cantidad, archivo);
if (elementosEscritos != cantidad) {
perror("Error al escribir en el archivo");
}
fclose(archivo);
}
void cargarEmpleados(const char *nombreArchivo, Empleado *empleados, size_t cantidad) {
FILE *archivo = fopen(nombreArchivo, "rb");
if (archivo == NULL) {
perror("Error al abrir el archivo para lectura");
exit(EXIT_FAILURE);
}
size_t elementosLeidos = fread(empleados, sizeof(Empleado), cantidad, archivo);
if (elementosLeidos != cantidad) {
perror("Error al leer del archivo");
}
fclose(archivo);
}
int main() {
Empleado listaEmpleados[2];
// Inicializar datos
listaEmpleados[0].id = 1;
strcpy(listaEmpleados[0].nombre, "Ana Martín");
listaEmpleados[0].salario = 3000.0f;
listaEmpleados[1].id = 2;
strcpy(listaEmpleados[1].nombre, "Luis Sánchez");
listaEmpleados[1].salario = 3500.5f;
// Serializar estructuras
guardarEmpleados("empleados.dat", listaEmpleados, 2);
// Limpiar datos
memset(listaEmpleados, 0, sizeof(listaEmpleados));
// Deserializar estructuras
cargarEmpleados("empleados.dat", listaEmpleados, 2);
// Mostrar datos
for (size_t i = 0; i < 2; i++) {
printf("ID: %d\n", listaEmpleados[i].id);
printf("Nombre: %s\n", listaEmpleados[i].nombre);
printf("Salario: %.2f\n\n", listaEmpleados[i].salario);
}
return 0;
}
En este ejemplo:
- Se define una estructura
Empleado
que contiene un entero, una cadena de caracteres y un número de punto flotante. - La función
guardarEmpleados()
utilizafwrite()
para escribir el arreglo de estructuras en un archivo binario. - La función
cargarEmpleados()
utilizafread()
para leer las estructuras desde el archivo y reconstruir el arreglo. - Se emplea
memset()
para limpiar el contenido del arreglo antes de la deserialización, garantizando que los datos se cargan correctamente.
Precauciones adicionales:
Compatibilidad de datos: Si se comparte el archivo binario entre sistemas con arquitecturas diferentes, es posible que surjan problemas debido a la representación interna de los datos. Para mejorar la portabilidad, se recomienda utilizar tipos de datos de tamaño fijo, como los definidos en <stdint.h>
(e.g., int32_t
).
Endianness: El orden de los bytes en la memoria puede variar entre sistemas little-endian y big-endian. Esto afecta la forma en que se interpretan los datos binarios y puede causar errores al deserializar.
Alineación de estructuras: Los compiladores pueden introducir bytes de relleno para alinear los datos en memoria. Para controlar la alineación y eliminar el relleno, se puede utilizar el atributo packed
en GCC:
typedef struct __attribute__((packed)) {
int id;
char nombre[50];
float salario;
} Empleado;
Sin embargo, es importante tener en cuenta que eliminar la alineación puede afectar el rendimiento y debe usarse con cautela.
Serialización manual:
Otra opción es realizar una serialización manual de cada miembro de la estructura, escribiéndolos individualmente. Esto permite un mayor control sobre el formato y puede mejorar la compatibilidad entre diferentes sistemas.
void guardarEmpleadoManual(const char *nombreArchivo, Empleado *empleado) {
FILE *archivo = fopen(nombreArchivo, "wb");
if (archivo == NULL) {
perror("Error al abrir el archivo");
exit(EXIT_FAILURE);
}
fwrite(&(empleado->id), sizeof(int), 1, archivo);
fwrite(empleado->nombre, sizeof(char), 50, archivo);
fwrite(&(empleado->salario), sizeof(float), 1, archivo);
fclose(archivo);
}
void cargarEmpleadoManual(const char *nombreArchivo, Empleado *empleado) {
FILE *archivo = fopen(nombreArchivo, "rb");
if (archivo == NULL) {
perror("Error al abrir el archivo");
exit(EXIT_FAILURE);
}
fread(&(empleado->id), sizeof(int), 1, archivo);
fread(empleado->nombre, sizeof(char), 50, archivo);
fread(&(empleado->salario), sizeof(float), 1, archivo);
fclose(archivo);
}
Con la serialización manual, se controla explícitamente cómo se leen y escriben los datos de cada miembro, lo que puede ayudar a evitar problemas relacionados con la alineación y la portabilidad.
Formato de cadenas y funciones de formateo
El formato de cadenas y las funciones de formateo juegan un papel crucial en la entrada y salida de datos en C, especialmente al trabajar con archivos. Estas funciones permiten representar datos en un formato legible y estructurado, facilitando tanto la escritura como la lectura de información desde archivos.
Las funciones fprintf()
y fscanf()
son fundamentales para realizar operaciones de E/S formateada con archivos de texto. Proporcionan una manera flexible de escribir y leer datos con formatos específicos, utilizando especificadores de formato similares a los de printf()
y scanf()
.
Uso de fprintf()
para escribir en archivos
La función fprintf()
escribe datos formateados en un archivo abierto. Su sintaxis es:
int fprintf(FILE *stream, const char *format, ...);
stream
: Puntero al archivo donde se escribirá.format
: Cadena de formato que especifica cómo se deben representar los datos....
: Lista de argumentos que se insertarán en la cadena de formato.
Ejemplo de escritura con fprintf()
:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.txt", "w");
if (archivo == NULL) {
perror("Error al abrir el archivo");
return 1;
}
int id = 123;
char nombre[] = "María López";
float promedio = 8.75f;
fprintf(archivo, "ID: %d\n", id);
fprintf(archivo, "Nombre: %s\n", nombre);
fprintf(archivo, "Promedio: %.2f\n", promedio);
fclose(archivo);
return 0;
}
En este ejemplo:
- Se utiliza
fprintf()
para escribir datos formateados en el archivodatos.txt
. - Los especificadores de formato
%d
,%s
y%.2f
indican cómo se deben representar los datos. - El especificador
%.2f
formatea el número de punto flotante con dos decimales.
Uso de fscanf()
para leer desde archivos
La función fscanf()
lee datos formateados desde un archivo abierto. Su sintaxis es:
int fscanf(FILE *stream, const char *format, ...);
stream
: Puntero al archivo desde donde se leerá.format
: Cadena de formato que especifica cómo se deben interpretar los datos....
: Punteros a variables donde se almacenarán los valores leídos.
Ejemplo de lectura con fscanf()
:
#include <stdio.h>
int main() {
FILE *archivo = fopen("datos.txt", "r");
if (archivo == NULL) {
perror("Error al abrir el archivo");
return 1;
}
int id;
char nombre[50];
float promedio;
fscanf(archivo, "ID: %d\n", &id);
fscanf(archivo, "Nombre: %[^\n]\n", nombre);
fscanf(archivo, "Promedio: %f\n", &promedio);
printf("ID: %d\n", id);
printf("Nombre: %s\n", nombre);
printf("Promedio: %.2f\n", promedio);
fclose(archivo);
return 0;
}
En este código:
- Se lee cada línea del archivo utilizando
fscanf()
con los mismos especificadores de formato utilizados en la escritura. - El especificador
%[^\n]
permite leer una línea completa hasta encontrar un salto de línea, capturando nombres con espacios.
Especificadores de formato comunes
Al utilizar funciones de formateo, es esencial conocer los especificadores de formato disponibles:
%d
: Enteros decimales con signo.%u
: Enteros decimales sin signo.%f
: Números de punto flotante en notación decimal.%s
: Cadenas de caracteres terminadas en nulo.%c
: Caracter individual.%x
,%X
: Enteros en notación hexadecimal.%o
: Enteros en notación octal.
Además, se pueden usar modificadores para ajustar la salida:
- Ancho de campo: Especifica el número mínimo de caracteres a imprimir.
- Precisión: Define el número de dígitos después del punto decimal para números de punto flotante.
- Banderas: Como
-
para alineación a la izquierda o0
para rellenar con ceros.
Ejemplo con modificadores de formato:
float valor = 3.1416f;
printf("Valor con dos decimales: %.2f\n", valor);
printf("Valor en un campo de 10 espacios: %10.2f\n", valor);
printf("Valor alineado a la izquierda: %-10.2ffin\n", valor);
Salida:
Valor con dos decimales: 3.14
Valor en un campo de 10 espacios: 3.14
Valor alineado a la izquierda: 3.14 fin
Formateo de cadenas con sprintf()
y sscanf()
Las funciones sprintf()
y sscanf()
permiten realizar operaciones de formateo sobre cadenas en memoria, sin interactuar con archivos ni la consola.
sprintf()
: Escribe datos formateados en una cadena de caracteres.sscanf()
: Lee datos formateados desde una cadena de caracteres.
Ejemplo de uso de sprintf()
:
#include <stdio.h>
int main() {
char buffer[100];
int edad = 25;
float altura = 1.75f;
sprintf(buffer, "Edad: %d años, Altura: %.2f metros", edad, altura);
printf("%s\n", buffer);
return 0;
}
En este ejemplo, sprintf()
construye una cadena formateada almacenada en buffer
.
Ejemplo de uso de sscanf()
:
#include <stdio.h>
int main() {
char datos[] = "Producto:12345 Precio:59.99";
int codigo;
float precio;
sscanf(datos, "Producto:%d Precio:%f", &codigo, &precio);
printf("Código: %d\n", codigo);
printf("Precio: %.2f\n", precio);
return 0;
}
Aquí, sscanf()
extrae valores numéricos de una cadena con un formato conocido.
Precauciones al usar funciones de formateo
- Seguridad: Al utilizar funciones como
sprintf()
, es importante asegurarse de que el buffer es lo suficientemente grande para contener la cadena resultante, evitando desbordamientos. Para prevenir este riesgo, se recomienda utilizarsnprintf()
, que limita el número de caracteres a escribir.
snprintf(buffer, sizeof(buffer), "Mensaje: %s", cadena);
- Validación de entrada: Al leer con
fscanf()
osscanf()
, verifica siempre que los datos se hayan leído correctamente comprobando el valor de retorno de la función.
int leidos = fscanf(archivo, "%d", &valor);
if (leidos != 1) {
// Manejar el error
}
- Especificadores adecuados: Utiliza los especificadores de formato que correspondan al tipo de datos que estás manejando para evitar comportamientos indefinidos.
Formato personalizado para estructuras complejas
Al manejar estructuras complejas, es posible definir funciones de formateo específicas que faciliten la escritura y lectura de datos estructurados.
Ejemplo de función personalizada con fprintf()
:
void escribirProducto(FILE *archivo, Producto p) {
fprintf(archivo, "%d,%s,%.2f\n", p.id, p.nombre, p.precio);
}
Ejemplo de función personalizada con fscanf()
:
int leerProducto(FILE *archivo, Producto *p) {
return fscanf(archivo, "%d,%49[^,],%f\n", &p->id, p->nombre, &p->precio);
}
En estos ejemplos:
- Se utiliza
,
como separador de campos en el archivo. - El especificador
%49[^,]
lee hasta 49 caracteres o hasta encontrar una coma, evitando desbordamientos.
Manejo de formatos variables
En algunos casos, puede ser necesario manejar formatos variables o desconocidos de antemano. Las funciones de la familia vfprintf()
, vscanf()
, etc., permiten trabajar con listas de argumentos variables, aunque su uso es más avanzado y requiere conocimiento de la biblioteca <stdarg.h>
.
Conclusión práctica
El dominio de las funciones de formateo y el correcto uso de los especificadores de formato son esenciales para manejar eficientemente la E/S en C. Estas herramientas permiten crear programas más robustos y flexibles, facilitando la interacción con archivos y la presentación de datos de manera clara y precisa.
Todas las lecciones de C
Accede a todas las lecciones de C y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A C
Introducción Y Entorno
Primer Programa En C
Introducción Y Entorno
Estructura Básica De Un Programa En C
Sintaxis
Operadores Y Expresiones
Sintaxis
Control De Flujo
Sintaxis
Arrays Y Manejo De Cadenas
Sintaxis
Funciones
Funciones Y Punteros
Punteros
Funciones Y Punteros
Gestión De Memoria Dinámica
Funciones Y Punteros
Estructuras En C
Estructuras, Uniones Y Tipos
Uniones Y Enumeraciones
Estructuras, Uniones Y Tipos
Typedef Y Y Organización De Código
Estructuras, Uniones Y Tipos
Archivos
Io Y Archivos
E/s Binaria Y Formateo
Io Y Archivos
Manipulación Avanzada De Cadenas
Io Y Archivos
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender la diferencia entre archivos de texto y archivos binarios.
- Manejar la sintaxis y uso de
fread()
yfwrite()
en C. - Realizar operaciones básicas de lectura y escritura de archivos binarios.
- Conocer las implicancias de
endianness
y portabilidad en archivos binarios. - Aplicar prácticas seguras al trabajar con archivos binarios para manejo de errores y eficiente almacenamiento.