headers fichero escribir dev cabeceras cabecera binarios binario archivos c++ c binaryfiles

c++ - dev - escribir en fichero binario c



Qué poner en el encabezado de un archivo de datos binarios (12)

Tengo una simulación que lee grandes archivos de datos binarios que creamos (de 10 a 100 s de GB). Usamos binario por razones de velocidad. Estos archivos dependen del sistema, se convierten a partir de archivos de texto en cada sistema que ejecutamos, por lo que no estoy preocupado por la portabilidad. Los archivos actualmente son muchas instancias de una estructura POD, escrita con fwrite.

Necesito cambiar la estructura, por lo que quiero agregar un encabezado que tenga un número de versión de archivo, que se incrementará cada vez que cambie la estructura. Como estoy haciendo esto, también quiero agregar otra información. Estoy pensando en el tamaño de la estructura, orden de bytes, y tal vez el número de versión svn del código que creó el archivo binario. ¿Hay algo más que sería útil agregar?


@rstevens dijo ''un identificador para el tipo de archivo'' ... buen consejo. Convencionalmente, eso se llama un número mágico y, en un archivo, no es un término de abuso (a diferencia del código, donde es un término de abuso). Básicamente, es un número, generalmente de al menos 4 bytes, y normalmente aseguro que al menos uno de esos bytes no es ASCII, que puede usar para validar que el archivo es del tipo que espera con una baja probabilidad de confusión. . También puede escribir una regla en / etc / magic (o equivalente local) para informar que los archivos que contienen su número mágico son su tipo de archivo especial.

Debe incluir un número de versión de formato de archivo. Sin embargo, recomendaría no usar el número SVN del código. Su código puede cambiar cuando el formato del archivo no.


Además de la información que necesite para el control de versiones de esquema, agregue detalles que pueden ser valiosos si está solucionando un problema. Por ejemplo:

  • marcas de tiempo de cuando se creó el archivo y actualización (si corresponde).
  • la cadena de versión de la compilación (lo ideal es que tenga una cadena de versión que se incrementa automáticamente en cada compilación ''oficial'' ... esto es diferente a la versión del esquema del archivo).
  • el nombre del sistema que crea el archivo y tal vez otras estadísticas que sean relevantes para su aplicación

Consideramos que esto es muy útil (a) para obtener información que de otra manera tendríamos que solicitar al cliente y (b) para obtener la información correcta: es sorprendente cuántos clientes informan que están ejecutando una versión diferente del software para lo que reclamos de datos!


Para archivos grandes, es posible que desee agregar definiciones de datos, por lo que su formato de archivo se autodescribe.


Para los binarios grandes, además del número de versión, tiendo a poner un conteo de registros y CRC, la razón es que los binarios grandes son mucho más propensos a ser truncados y / o corrompidos con el tiempo o durante la transferencia que los pequeños. Recientemente, me horroriza que Windows no maneje esto bien, ya que utilicé el explorador para copiar unos 2TB en un par de cientos de archivos en un dispositivo NAS conectado, y encontré que 2-3 archivos en cada copia estaban dañados (no completamente copiado).


Puede considerar colocar un desplazamiento de archivo en una posición fija en el encabezado, que le indica dónde comienzan los datos reales en el archivo. Esto le permitirá cambiar el tamaño del encabezado cuando sea necesario.

En un par de casos, puse el valor 0x12345678 en el encabezado para poder detectar si el formato del archivo coincidía con el endianismo de la máquina que lo estaba procesando.


Si está colocando un número de versión en el encabezado, puede cambiar esa versión cada vez que necesite cambiar la estructura POD o agregar nuevos campos al encabezado.

Así que no agregue cosas al encabezado ahora porque podría ser interesante. Solo está creando un código que debe mantener pero que tiene poco valor real.


Si son tan grandes, me reservaría un pedazo saludable (64K?) De espacio al comienzo del archivo y pondría los metadatos allí en formato XML seguido de un carácter de fin de archivo (Ctrl-Z para DOS / Windows, ctrl-D para Unix?). De esta forma, puede examinar y analizar fácilmente los metadatos con la amplia gama de conjuntos de herramientas para XML.

De lo contrario, voy con lo que otras personas ya han dicho: marca de tiempo para la creación de archivos, identificador para qué máquina se creó, básicamente cualquier otra cosa que se pueda imaginar para fines de diagnóstico. E idealmente incluiría la definición del formato de la estructura en sí. Si está cambiando la estructura a menudo, es un gran problema mantener la versión correcta del código para leer varios formatos de archivos de datos antiguos.

Una gran ventaja de HDF5, como ha mencionado @highpercomp, es que no tiene que preocuparse por los cambios en el formato de la estructura, siempre que tenga alguna convención sobre los nombres y los tipos de datos. Los nombres de las estructuras y los tipos de datos están almacenados en el archivo, por lo que puede arruinar su código C y no importa, aún puede recuperar datos de un archivo HDF5. Le permite preocuparse menos por el formato de los datos y más en la estructura de los datos, es decir, no me importa la secuencia de bytes, ese es el problema de HDF5, pero me preocupan los nombres de los campos y cosas por el estilo.

Otra razón por la que me gusta HDF5 es que puede optar por usar compresión, lo que le lleva una cantidad muy pequeña de tiempo y le puede dar grandes ganancias en el espacio de almacenamiento si los datos cambian lentamente o casi lo mismo excepto por algunos errores errantes de interés.


Un identificador para el tipo de archivo sería útil si posteriormente tendrá otras estructuras escritas en archivos binarios. Tal vez esto podría ser una cadena corta para que pueda ver con una mirada en el archivo (a través del editor hexadecimal) lo que contiene.


Para binarios grandes miraría seriamente HDF5 (Google para eso). Incluso si no es algo que quiera adoptar, podría indicarle algunas direcciones útiles para diseñar sus propios formatos.


Como mi experiencia con la configuración de equipos de telecomunicaciones y las actualizaciones de firmware muestra que realmente solo necesita varios bytes predefinidos al principio (esto es importante), que comienza desde la versión (parte fija del encabezado). El resto del encabezado es opcional, al indicar la versión adecuada siempre puede mostrar cómo procesarlo. Lo importante aquí es que es mejor colocar la parte ''variable'' del encabezado al final del archivo. Si planea operaciones en el encabezado sin modificar el contenido del archivo. También esto simplifica las operaciones de ''agregar'' que deberían recalcular la parte del encabezado variable.

Es bueno tener características para el encabezado de tamaño fijo (al principio):

  • Campo común de ''longitud'' (incluido el encabezado).
  • Algo así como CRC32 (incluido el encabezado).

OK, para XML de parte variable o algún formato bastante extensible en el encabezado es una buena idea, pero ¿es realmente necesario? Tenía mucha experiencia con la codificación ASN ... en la mayoría de los casos se sobrepasó su uso.

Bueno, tal vez tengas una comprensión adicional cuando mires cosas como el formato TPKT que se describe en RFC 2126 (capítulo 4.3).


Mi variación combina los enfoques de Roddy y Jason S.

En resumen: ponga los metadatos de texto formateados al final del archivo con una forma de determinar su longitud almacenada en otro lugar.

1) Ponga un campo de longitud al principio de su archivo para que sepa la longitud de los metadatos al final en lugar de asumir una longitud fija. De esta forma, para obtener los metadatos, simplemente lee ese campo inicial de longitud fija y luego obtiene el blob de metadatos del final del archivo.

2) Use XML o YAML o JSON para los metadatos. Esto es especialmente útil / seguro si los metadatos se agregan al final porque nadie que lea el archivo automáticamente pensará que todo es XML solo porque comienza con XML.

La única desventaja de este enfoque es que cuando sus metadatos crecen, debe actualizar tanto el encabezado del archivo como la cola, pero es probable que otras partes se hayan actualizado de todos modos. Si solo está actualizando trivialidades como una fecha de último acceso, la longitud de los metadatos no cambiará, por lo que solo necesita una actualización en el lugar.


En mi experiencia, cuestionar los datos que necesitará es invariablemente tiempo perdido. Lo importante es estructurar sus metadatos de una manera que sea extensible. Para archivos XML, eso es sencillo, pero los archivos binarios requieren un poco más de reflexión.

Tiendo a almacenar metadatos en una estructura al final del archivo, no al principio. Esto tiene dos ventajas:

  • Los archivos truncados / sin terminar se detectan fácilmente.
  • Los pies de página de metadatos a menudo se pueden agregar a los archivos existentes sin afectar su código de lectura.

El pie de página de metadatos más simple que uso se parece a esto:

struct MetadataFooter{ char[40] creatorVersion; char[40] creatorApplication; .. or whatever } struct FileFooter { int64 metadataFooterSize; // = sizeof(MetadataFooter) char[10] magicString; // a unique identifier for the format: maybe "MYFILEFMT" };

Después de los datos brutos, se escriben el pie de página de metadatos y ENTONCES el pie de página del archivo.

Al leer el archivo, busque hasta el final - sizeof (FileFooter). Lea el pie de página y verifique magicString. Luego, busca de acuerdo con metadataFooterSize y lee los metadatos. Dependiendo del tamaño del pie de página contenido en el archivo, puede usar valores predeterminados para los campos faltantes.

Como señala KeithB , incluso podría usar esta técnica para almacenar los metadatos como una cadena XML, lo que le da las ventajas de ambos metadatos totalmente extensibles, con la compacidad y velocidad de los datos binarios.