Domanda

Ho una simulazione che legge file di dati binari di grandi dimensioni che creiamo (da 10 a 100s di GB). Usiamo il binario per motivi di velocità. Questi file dipendono dal sistema, convertiti da file di testo su ciascun sistema che eseguiamo, quindi non sono preoccupato per la portabilità. I file attualmente sono molte istanze di una struttura POD, scritta con fwrite.

Ho bisogno di cambiare la struttura, quindi voglio aggiungere un'intestazione che contenga un numero di versione del file, che verrà incrementato ogni volta che cambia la struttura. Dal momento che sto facendo questo, voglio aggiungere anche alcune altre informazioni. Sto pensando alla dimensione della struttura, all'ordine dei byte e forse al numero di versione svn del codice che ha creato il file binario. C'è qualcos'altro che sarebbe utile aggiungere?

È stato utile?

Soluzione

Nella mia esperienza, indovinare i dati di cui hai bisogno è sempre tempo perso. L'importante è strutturare i tuoi metadati in modo estensibile. Per i file XML, è semplice, ma i file binari richiedono un po 'più di riflessione.

Tendo a memorizzare i metadati in una struttura alla fine del file, non all'inizio. Questo ha due vantaggi:

  • I file troncati / non terminati sono facilmente rilevabile.
  • Spesso possono essere i piè di pagina dei metadati aggiunto a file esistenti senza influenzando il loro codice di lettura.

Il piè di pagina dei metadati più semplice che uso assomiglia a questo:

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"
};

Dopo i dati non elaborati, vengono scritti il ??piè di pagina dei metadati e POI il piè di pagina del file.

Quando leggi il file, cerca fino alla fine - sizeof (FileFooter). Leggi il piè di pagina e verifica magicString. Quindi, cercare indietro in base a metadataFooterSize e leggere i metadati. A seconda delle dimensioni del piè di pagina contenute nel file, puoi utilizzare i valori predefiniti per i campi mancanti.

Come sottolinea KeithB , potresti persino utilizzare questa tecnica per archiviare i metadati come stringa XML, offrendo i vantaggi di entrambi i metadati totalmente estensibili, con la compattezza e la velocità dei dati binari.

Altri suggerimenti

Per i file binari di grandi dimensioni prenderei in seria considerazione HDF5 (Google per questo). Anche se non è qualcosa che vuoi adottare, potrebbe indirizzarti in alcune indicazioni utili nella progettazione dei tuoi formati.

Per i binari di grandi dimensioni, oltre al numero di versione, tendo a mettere un numero di record e CRC, il motivo è che i binari di grandi dimensioni sono molto più inclini a essere troncati e / o danneggiati nel tempo o durante il trasferimento rispetto a quelli più piccoli. Ho scoperto di recente con mio orrore che Windows non lo gestisce affatto bene, poiché ho usato Explorer per copiare circa 2 TB su un paio di centinaia di file su un dispositivo NAS collegato e ho scoperto che 2-3 file su ogni copia erano danneggiati (non completamente copiato).

Un identificatore per il tipo di file sarebbe utile se in seguito avrai altre strutture scritte su file binari. Forse questa potrebbe essere una stringa breve in modo da poter vedere con uno sguardo al file (tramite l'editor esadecimale) cosa contiene.

Se sono così grandi, riserverei un grosso spazio (64 KB?) di spazio all'inizio del file e inserisco i metadati in formato XML seguito da un carattere di fine file (Ctrl-Z per DOS / Windows, ctrl-D per unix?). In questo modo puoi esaminare e analizzare facilmente i metadati con la vasta gamma di set di strumenti disponibili per XML.

Altrimenti vado con ciò che altre persone hanno già detto: timestamp per la creazione di file, identificatore per quale macchina è stata creata, praticamente qualsiasi altra cosa che si possa pensare a scopi diagnostici. E idealmente dovresti includere la definizione del formato della struttura stessa. Se stai cambiando spesso la struttura, è molto difficile mantenere la versione corretta del codice per leggere vari formati di vecchi file di dati.

Un grande vantaggio di HDF5, come accennato da @highpercomp, è che non devi preoccuparti di cambiamenti nel formato della struttura, purché tu abbia una convenzione su quali siano i nomi e i tipi di dati. I nomi e i tipi di dati della struttura sono tutti memorizzati nel file stesso, quindi puoi mandare in frantumi il tuo codice C e non importa, puoi comunque recuperare i dati da un file HDF5. Ti consente di preoccuparti meno del formato dei dati e di più sulla struttura dei dati, cioè non mi interessa la sequenza di byte, questo è il problema di HDF5, ma io prenditi cura dei nomi dei campi e simili.

Un altro motivo per cui mi piace l'HDF5 è che puoi scegliere di usare la compressione, che richiede una quantità di tempo molto piccola e può darti enormi vittorie nello spazio di archiviazione se i dati cambiano lentamente o per lo più lo stesso, tranne per alcuni blip errati di interesse.

@rstevens ha detto 'un identificatore per il tipo di file' ... un buon consiglio. Convenzionalmente, si chiama numero magico e, in un file, non è un termine di abuso (a differenza del codice, dove è un termine di abuso). Fondamentalmente, è un certo numero - in genere almeno 4 byte, e di solito mi assicuro che almeno uno di quei byte non sia ASCII - che puoi usare per confermare che il file è del tipo che ti aspetti con una bassa probabilità di essere confuso . Puoi anche scrivere una regola in / etc / magic (o equivalente locale) per segnalare che i file che contengono il tuo numero magico sono il tuo tipo di file speciale.

È necessario includere un numero di versione del formato file. Tuttavia, consiglierei di non utilizzare il numero SVN del codice. Il tuo codice può cambiare quando il formato del file non lo è.

Oltre alle informazioni necessarie per il controllo delle versioni dello schema, aggiungi dettagli che potrebbero essere utili se stai risolvendo un problema. Ad esempio:

  • data e ora di creazione e aggiornamento del file (se applicabile).
  • la stringa di versione dalla build (idealmente hai una stringa di versione che viene auto-incrementata su ogni build 'ufficiale' ... questo è diverso dalla versione dello schema dei file).
  • il nome del sistema che crea il file e forse altre statistiche pertinenti alla tua app

Riteniamo che ciò sia molto utile (a) per ottenere informazioni che altrimenti dovremmo chiedere al cliente di fornire e (b) ottenere informazioni corrette - è sorprendente quanti clienti dichiarino di eseguire una versione diversa del software a ciò che affermano i dati!

Potresti considerare di inserire un offset di file in una posizione fissa nell'intestazione, che ti dice dove iniziano i dati effettivi nel file. Ciò ti consentirebbe di modificare la dimensione dell'intestazione quando necessario.

In un paio di casi, ho messo il valore 0x12345678 nell'intestazione in modo da poter rilevare se il formato del file corrispondeva all'endianismo della macchina che lo stava elaborando.

Come dimostra la mia esperienza con la configurazione delle apparecchiature di telecomunicazione e gli aggiornamenti del firmware, all'inizio sono necessari solo diversi byte predefiniti (questo è importante) che parte dalla versione (parte fissa dell'intestazione). Il resto dell'intestazione è facoltativo, indicando la versione corretta puoi sempre mostrare come elaborarlo. La cosa importante qui è che è meglio posizionare la parte 'variabile' dell'intestazione alla fine del file. Se si pianificano operazioni sull'intestazione senza modificare il contenuto del file stesso. Anche questo semplifica le operazioni "append" che dovrebbero ricalcolare la parte di intestazione variabile.

Bello avere funzionalità per l'intestazione a dimensione fissa (all'inizio):

  • Campo 'lunghezza' comune (compresa l'intestazione).
  • Qualcosa come CRC32 (compresa l'intestazione).

OK, per XML parte variabile o un formato abbastanza estensibile nell'intestazione è una buona idea ma è davvero necessario? Ho avuto molta esperienza con la codifica ASN ... nella maggior parte dei casi il suo utilizzo è stato superato.

Bene, forse avrai ulteriore comprensione quando guardi cose come il formato TPKT che è descritto in RFC 2126 (capitolo 4.3).

Se si inserisce un numero di versione nell'intestazione, è possibile modificarla ogni volta che è necessario modificare la struttura POD o aggiungere nuovi campi all'intestazione.

Quindi non aggiungere roba all'intestazione ora perché potrebbe essere interessante. Stai solo creando codice che devi mantenere ma che ha poco valore reale.

Per file di grandi dimensioni, potresti voler aggiungere definizioni di dati, quindi il tuo formato di file diventa auto-descrittivo.

La mia variazione combina gli approcci di Roddy e Jason S.

In sintesi: inserisci metadati di testo formattati alla fine del file in modo da determinarne la lunghezza memorizzata altrove.

1) Metti un campo di lunghezza all'inizio del tuo file in modo da conoscere la lunghezza dei metadati alla fine anziché assumere una lunghezza fissa. In questo modo, per ottenere i metadati basta leggere quel campo iniziale a lunghezza fissa e quindi ottenere il BLOB di metadati dalla fine del file.

2) Utilizzare XML o YAML o JSON per i metadati. Ciò è particolarmente utile / sicuro se i metadati vengono aggiunti alla fine perché nessuno che legge il file penserà automaticamente che sia tutto XML solo perché inizia con XML.

L'unico svantaggio di questo approccio è quando i tuoi metadati crescono, devi aggiornare sia la testa del file che la coda ma è probabile che altre parti siano state comunque aggiornate. Se sta semplicemente aggiornando le curiosità come una data dell'ultimo accesso, la lunghezza dei metadati non cambierà, quindi necessita solo di un aggiornamento sul posto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top