Pregunta

Tengo una simulación que lee grandes archivos de datos binarios que creamos (10s a 100s de GB). Utilizamos binarios por razones de velocidad. Estos archivos dependen del sistema, se convierten de archivos de texto en cada sistema que ejecutamos, por lo que no me preocupa la portabilidad. Los archivos actualmente son muchas instancias de una estructura POD, escritas 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. Ya que estoy haciendo esto, quiero agregar otra información también. Estoy pensando en el tamaño de la estructura, el 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?

¿Fue útil?

Solución

En mi experiencia, suponer en segundo lugar los datos que necesitará es una pérdida de tiempo invariable. Lo importante es estructurar sus metadatos de forma extensible. Para los 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 / no terminados son fácilmente detectable.
  • Los pies de página de metadatos a menudo pueden ser adjuntado a los archivos existentes sin impactando 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 sin procesar, se escriben el pie de metadatos y, ENTONCES, el pie de página del archivo.

Al leer el archivo, busque el tamaño final (FileFooter). Lee el pie de página, y verifica el magicString. Luego, busque de nuevo según metadataFooterSize y lea los metadatos. Dependiendo del tamaño del pie de página contenido en el archivo, puede usar valores predeterminados para los campos que faltan.

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

Otros consejos

Para binarios grandes, me gustaría ver seriamente HDF5 (Google para ello). Incluso si no es algo que quiere adoptar, podría indicar algunas instrucciones útiles para diseñar sus propios formatos.

Para los binarios grandes, además del número de versión, tiendo a poner un conteo récord 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 más pequeños. Recientemente, para mi horror, descubrí que Windows no maneja esto bien, ya que utilicé el explorador para copiar aproximadamente 2TB en un par de cientos de archivos a un dispositivo NAS conectado, y encontré que 2-3 archivos en cada copia estaban dañados (no completamente) copiado).

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

Si son tan grandes, reservaría una buena parte (64K?) de espacio al principio del archivo y pondría los metadatos allí en formato XML seguido de un carácter de final de archivo (Ctrl-Z para DOS / Windows, ctrl-D para unix?). De esa manera, puede examinar y analizar los metadatos fácilmente con la amplia gama de herramientas disponibles 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 la máquina en la que se creó, básicamente cualquier otra cosa en la que pueda pensar para fines de diagnóstico. E idealmente incluirías la definición del formato de estructura en sí. Si cambia la estructura a menudo, es muy difícil mantener la versión correcta del código para leer varios formatos de archivos de datos antiguos.

Una gran ventaja de HDF5, como lo ha mencionado @highpercomp, es que simplemente no tiene que preocuparse por los cambios en el formato de la estructura, siempre que tenga alguna idea de cuáles son los nombres y tipos de datos. Los nombres de la estructura y los tipos de datos se almacenan en el propio archivo, por lo que puede volar su código C a smithereens 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 sobre la estructura de los datos, es decir, no me importa la secuencia de bytes, ese es el problema de HDF5, pero preocuparse por los nombres de campos y similares.

Otra razón por la que me gusta HDF5 es que puede elegir usar la compresión, que toma una cantidad muy pequeña de tiempo y puede brindarle grandes ganancias en el espacio de almacenamiento si los datos cambian lentamente o son prácticamente los mismos, excepto por algunos errores intermitentes. de interés.

@rstevens dijo 'un identificador para el tipo de archivo' ... un 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 generalmente me aseguro de que al menos uno de esos bytes no sea 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 del esquema, agregue detalles que pueden ser valiosos si está resolviendo un problema. Por ejemplo:

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

Encontramos que esto es muy útil (a) para obtener información, de lo contrario tendríamos que pedirle al cliente que proporcione y (b) obtener información correcta: es sorprendente la cantidad de clientes que informan que están ejecutando una versión diferente del software. a lo que afirman los datos!

Puede considerar colocar un desplazamiento de archivo en una posición fija en el encabezado, lo que le indica dónde comienzan los datos reales en el archivo. Esto le permitiría 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.

Como mi experiencia con la configuración del equipo de telecomunicaciones y las actualizaciones de firmware muestra que solo necesita realmente algunos 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 correcta, 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 'anexas' que deberían recalcular la parte del encabezado variable.

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

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

OK, para una parte variable XML 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, su uso fue sobrepasado.

Bueno, quizás tengas un entendimiento adicional cuando veas cosas como el formato TPKT que se describe en RFC 2126 (capítulo 4.3).

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

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

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

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

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

1) Coloque 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 esa manera, para obtener los metadatos que acaba de leer ese campo inicial de longitud fija y luego obtener el blob de metadatos desde el 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 pensará automáticamente que todo es XML solo porque comienza con XML.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top