Archivos (6): volcar en archivos con fwrite

En este vídeo vamos a ver cómo podemos usar la primitiva fwrite para transferir regiones de memoria a streams o archivos, para permitir serializar de forma pura estructuras o arrays complejos de una manera mucho más precisa que trabajando con cadenas de caracteres.

Cuando trabajamos con archivos en C, normalmente pensamos en guardar texto, caracteres o cadenas que podamos leer fácilmente con un editor. Sin embargo, cuando manejamos datos más complejos, como estructuras con múltiples campos de distintos tipos, esta forma de almacenamiento se vuelve poco práctica. Convertir cada campo a texto y luego parsearlo para recuperarlo puede ser tedioso y poco eficiente.

En lugar de eso, podemos aprovechar que en memoria todo se representa como bytes. Por ejemplo, si tenemos una estructura que almacena una medición con campos para año, mes, día, temperatura, índice ultravioleta y viento, todos esos datos están almacenados contiguamente en memoria como una secuencia de bytes. En C, podemos tratar esa estructura no como un conjunto de variables, sino como un bloque de memoria, un buffer, y volcarlo directamente a un archivo binario.

Para hacer esto, usamos la función fwrite. Esta función nos permite escribir en un archivo un bloque de memoria, sin importar el tipo de datos que contenga. Su primer parámetro es un puntero void * que apunta al inicio del buffer que queremos escribir. Esto significa que no importa si es un puntero a una estructura, a un entero o a un flotante; fwrite solo ve bytes.

El segundo parámetro es el tamaño en bytes de cada elemento que queremos escribir. Normalmente usamos sizeof para obtener el tamaño exacto de la estructura o del tipo de dato que estamos guardando, asegurándonos de escribir la cantidad correcta de bytes.

El tercer parámetro indica cuántos elementos de ese tamaño queremos escribir. Por ejemplo, si tenemos un array de estructuras, podemos pedir que se escriban varias consecutivamente. En nuestro caso, si solo queremos escribir una estructura, ponemos uno.

Finalmente, el cuarto parámetro es el puntero al archivo abierto con fopen. Es importante abrir el archivo en modo binario, usando "wb", para evitar que el sistema operativo realice transformaciones automáticas en los bytes, como convertir saltos de línea, lo que podría corromper los datos.

Veamos un ejemplo sencillo que ilustra cómo escribir una estructura en un archivo binario:

#include <stdio.h>

struct medicion {
    int año;
    int mes;
    int dia;
    float temperatura;
    int indice_uv;
    int viento;
};

int main() {
    struct medicion medida = {2020, 11, 9, 12.5f, 4, 15};

    FILE *fp = fopen("temperatura.bin", "wb");
    if (fp == NULL) {
        perror("Error al abrir el archivo");
        return 1;
    }

    size_t elementos_escritos = fwrite(&medida, sizeof(struct medicion), 1, fp);
    if (elementos_escritos != 1) {
        perror("Error al escribir en el archivo");
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

En este código, definimos la estructura medicion con varios campos. Creamos una variable medida con valores concretos. Abrimos un archivo binario para escritura y usamos fwrite para volcar la estructura completa en el archivo. Comprobamos que la escritura haya sido exitosa y cerramos el archivo.

Al abrir el archivo resultante con un editor de texto, veremos caracteres extraños o basura, porque no es un archivo de texto sino un archivo binario que contiene la representación en bytes de la estructura. Para inspeccionarlo, podemos usar herramientas como xxd en sistemas Unix, que muestran el contenido hexadecimal del archivo.

Este método es muy eficiente para guardar y recuperar datos complejos, ya que evita la conversión a texto y la posterior interpretación. En próximas ocasiones veremos cómo leer estos datos con fread para reconstruir las estructuras en memoria. Por ahora, hemos dado un paso importante para manejar archivos binarios en C y trabajar directamente con bloques de memoria.

Lista de reproducción
  1. 1
    Instalar CodeBlocks
    15 minutos
  2. 2
    Funciones y hola mundo
    17 minutos
  3. 3
    Variables y tipos de datos
    17 minutos
  4. 4
    Condicionales y operadores lógicos
    16 minutos
  5. 5
    Bucles
    11 minutos
  6. 6
    Punteros
    12 minutos
  7. 7
    Arrays
    14 minutos
  8. 8
    Estructuras
    12 minutos
  9. 9
    Otras construcciones de C
    9 minutos
  10. 10
    Memoria dinámica
    8 minutos
  11. 11
    El preprocesador (parte 1)
    10 minutos
  12. 12
    El preprocesador (parte 2)
    9 minutos
  13. 13
    Archivos de cabecera y múltiples .c (parte 1)
    8 minutos
  14. 14
    Archivos de cabecera y múltiples .c (parte 2)
    9 minutos
  15. 15
    C desde la línea de comandos (parte 1)
    8 minutos
  16. 16
    C desde la línea de comandos (parte 2)
    9 minutos
  17. 17
    Break y continue
    10 minutos
  18. 18
    Goto
    13 minutos
  19. 19
    Manipulación de bits
    15 minutos
  20. 20
    Máscaras de bit
    19 minutos
  21. 21
    Archivos (1): fopen y fclose
    13 minutos
  22. 22
    Archivos (2): leer con fgetc
    9 minutos
  23. 23
    Archivos (3): fseek y ftell
    11 minutos
  24. 24
    Archivos (4): leer con fgets
    9 minutos
  25. 25
    Archivos (5): fputc y fputs
    7 minutos
  26. 26
    Archivos (6): volcar en archivos con fwrite
    10 minutos
  27. 27
    Archivos (7): fread, fwrite y los arrays
    10 minutos
  28. 28
    Archivos (8): entrada estándar y salida estándar
    9 minutos
  29. 29
    Archivos (9): buffers
    14 minutos
  30. 30
    Archivos (y 10): otras funciones útiles con archivos
    5 minutos
  31. 31
    printf (1)
    18 minutos
  32. 32
    printf (parte 2)
    12 minutos
  33. 33
    scanf (parte 1)
    17 minutos
  34. 34
    scanf (parte 2)
    17 minutos
  35. 35
    fprintf, sprintf y snprintf
    8 minutos
  36. 36
    Tipos de datos opacos
    13 minutos
  37. 37
    Bibliotecas estáticas
    13 minutos
  38. 38
    Bibliotecas dinámicas
    15 minutos
  39. 39
    Más flags: i mayúscula (include), wall, werror, pedantic...
    12 minutos
  40. 40
    pkg-config
    12 minutos
  41. 41
    Make
    17 minutos
  42. 42
    GDB
    21 minutos
  43. 43
    Variables globales
    6 minutos
  44. 44
    extern
    9 minutos
  45. 45
    Funciones variádicas
    12 minutos
  46. 46
    El optimizador de GCC y la opción -O
    12 minutos
  47. 47
    Volatile
    6 minutos