C'è qualche pericolo nello scrivere byte grezzi in un file? [chiuso]


12

Sto risolvendo un problema in Programming Pearls, in particolare l'implementazione di un programma che ordina un file contenente al massimo 10.000.000 di numeri interi (colonna 1, problema 3). Dal momento che il libro non specifica come i dati dovrebbero essere archiviati nel file, sto considerando di memorizzare gli interi come byte grezzi (ci sono altri vincoli che rendono una buona opzione i byte grezzi). Non ho mai lavorato a un livello così basso prima, quindi voglio sapere se c'è qualcosa di pericoloso che dovrei fare attenzione. Devo preoccuparmi di usare accidentalmente una sorta di sequenza di fine file quando scrivo byte grezzi in un file, ad esempio?

Modificare:

Ora capisco quanto fosse ampia la mia domanda. Intendevo davvero problemi di tipo più catastrofico, come sovrascrivere accidentalmente altri file sul disco. Mi dispiace non ero più chiaro in origine.


6
Nota che Programming Pearls è un libro molto antico; potresti facilmente leggere interi interi 10 ^ 7 in memoria su una moderna macchina desktop, fare l'ordinamento e scriverlo di nuovo. Per ottenere il punto originale di quel capitolo, limita la quantità che leggi in qualsiasi momento a una frazione del numero totale. Oppure, aumentare le dimensioni del file a circa 10 ^ 10 numeri interi.
Caleb,

3
In realtà, quando sento la parola "pericoloso", penso a cose che fanno esplodere il mio PC, eliminano i miei conti bancari o qualcosa del genere. E immagino sia molto probabile presumere che, fintanto che il tuo programma non viene utilizzato per controllare un Airbus o una centrale elettrica, non accadrà nulla di veramente "pericoloso" quando proverai ciò che hai in mente.
Doc Brown,


2
@delnan Anni fa, quando il mito del personaggio EOF era in voga, ricordo i sistemi di protezione dalla copia basati su "copia fino al personaggio EOF" che molti programmi di copia dell'epoca facevano. Alcuni programmi inseriscono dati aggiuntivi che dovrebbero verificare dopo il marker EOF di un file di testo associato, ma prima della fine allocata del file. Il programma di copia non copia i dati aggiuntivi convalidando un'installazione pulita ... ahh ... nostalgia.

Pericolo? Come in "il mio computer esploderà se lo faccio"? No.
jwenting

Risposte:


11

L'unico pericolo in cui ti imbatterai è la piccola e grande endianess (se il byte più o meno significativo viene scritto per primo). Tuttavia, se rimani nello stesso ambiente, non ci saranno problemi. oltre alla garanzia generale di scrivere / analizzare andata e ritorno.

Il file system è progettato per gestire qualsiasi sequenza di byte.


2
+1 per l'ultima riga. Non sono sicuro che il grande / piccolo problema sia l' unico problema - l'OP potrebbe ad esempio confondersi su dove si trovano i confini tra numeri interi. Ma buona risposta comunque.
Caleb,

27

No, in effetti questo è il numero di formati di file che funzionano. Esempi comuni di file binari come questo includono immagini e file musicali / audio.

Per mantenere l'integrità del file e dei dati letti da esso, assicurarsi di seguire queste linee guida:

  • Apri sempre il file (leggendo o scrivendo) usando la stessa modalità: testo o binario. La differenza principale è che la modalità di testo si preoccupa per le nuove righe e può "dividere" i caratteri delle nuove righe durante la lettura di un file (a seconda della libreria specifica utilizzata). La modalità testo può anche eseguire traduzioni Unicode che probabilmente si strozzeranno con dati non Unicode.
  • Quando leggi dati non stringa, assicurati di leggere usando lo stesso tipo di dati che scrivi. Ad esempio, se i primi quattro byte del file sono numeri interi descrittivi, assicurarsi di leggere e scrivere utilizzando un metodo che accetta / fornisce un numero intero per assicurarsi che sia trattato in modo coerente. Lo stesso tipo di dati può avere dimensioni diverse su macchine diverse e la miscelazione di tipi di dati sulla stessa macchina può anche cambiare il significato dei dati (ad es. Interpretare un bit nel mezzo di un intero più lungo come bit di segno).
  • Endianness: se la libreria che stai utilizzando non la gestisce in modo coerente, potrebbe essere necessario gestirla da solo. Ad esempio, Java utilizza sempre l'ordine dei byte di rete (big endian) per i tipi multi-byte. C e C ++ usano qualunque cosa abbia deciso l'implementatore della libreria, generalmente lo stesso del processore (little endian su Intel, big endian sulla maggior parte degli altri). Se questo è un esercizio rapido su un sistema non è così importante, ma è comunque una buona abitudine prestare attenzione a questo e codificarlo se necessario.

I dettagli specifici varieranno in base al framework, alla piattaforma e al linguaggio, ma questo dovrebbe coprire i "gotcha" di base con l'I / O dei file.


3
Un ulteriore punto per i dati non stringa: assicurarsi di utilizzare un numero consistente di byte per ciascun tipo. In C e C ++ un intpuò essere ovunque tra 2 e 8 o più byte (in realtà ottetti).
Bart van Ingen Schenau,

Ciò è implicitamente incluso nel mio secondo punto, ad esempio 32 v. 64 bit intero. Sarebbero tipi di dati diversi.

Potresti voler renderlo esplicito. Non è ovvio che intsu due macchine diverse potrebbero essere considerati tipi di dati diversi.
Bart van Ingen Schenau,

9

Oltre a tutti i gotchas già menzionati, se stai creando un nuovo formato di file binario piuttosto che leggere e scrivere dati in un formato esistente, è assolutamente vitale includere un'intestazione di file : un blocco di dati all'inizio del file che identifica in modo inequivocabile il formato del file e registra tutti i metadati che potrebbero essere richiesti.

Le buone intestazioni dei file includono almeno tre cose:

  • Un " numero magico ", di almeno quattro byte. Il numero magico DEVE essere rfc2119 essere i primissimi N byte nel file, DEVE non essere mai stato usato per nessun altro formato di file che è possibile scavare e DEVE contenere almeno un byte che non sia un carattere ASCII stampabile. Vedi le specifiche PNG per come progettare un numero magico davvero completo . Vedi il codice sorgente del file(1)comando per un database di numeri magici esistenti che è completo come probabilmente troverai.

    Il punto di un numero magico è di etichettare in modo inequivocabile il file, in banda, con il suo formato. Se non includi un numero magico o non è la prima cosa nel file, corri il rischio di programmi che identificano erroneamente il tuo file come qualche altro tipo di file, il che porta alla perdita di dati, al virus che fuoriesce dal rilevamento e ad altri catastrofi.

  • Un'indicazione della versione del formato del file. Anche se pensi che non dovrai mai rivedere drasticamente il tuo formato di file, crea i due byte successivi dopo il numero magico 00 00e documenta che questo è un numero di versione a 16 bit in un certo endianness (qualunque cosa ti piaccia, ma scegli uno e attenersi ad esso in tutto il file ) e verrà incrementato se il significato dei dati successivi cambia radicalmente. Il tuo sé futuro ti ringrazierà.

    (La specifica PNG prende una strada diversa qui, specificando che i formati di blocco sono congelati e che tutte le future modifiche al formato assumeranno la forma di nuovi tipi di blocco. È anche valido, ma raccomando l'approccio numero magico + numero versione per principianti all'elaborazione binaria dei dati. Le persone che hanno progettato PNG stavano attingendo da decenni di esperienza collettiva con i formati di immagine.)

  • Qualche tipo di meccanismo per incorporare metadati arbitrari nel file. Questo può essere semplice come avente le seguenti due byte essere un offset dalla fine dell'intestazione all'inizio dei dati effettivi 16 bit, con tutto il resto deve essere interpretato come coppie UTF-8 valore-chiave alla RFC 822 (ovvero " Tag: value\n" - se segui questa strada ti consiglio di non consentire la piegatura di linee lunghe). Ancora una volta, PNG è notevolmente più intelligente.


Non è necessario creare il tuo formato di file ... archivia i dati come immagine. Potrebbe essere necessario modificare la dimensionalità (ad es. 10k x 1k) in modo che sia supportato. Oppure potresti usare FITS . Se i tuoi dati sono più complessi di un singolo array, puoi utilizzare HDF , CDF o NetCDF .
Joe,

Suggerirei di mantenerlo semplice. 256 diverse versioni saranno sufficienti e, in caso contrario, versioni aggiuntive possono essere concepite come sovversioni della versione 255. Analogamente per i metadati, è sufficiente aggiungerli in una versione quando sono effettivamente necessari. @Joe Image ??? Stai evitando la potenziale confusione del formato confondendo prima tutti!
maaartinus,

@maaartinus Rendere il campo versione due byte costringe il progettista di formati a impegnarsi in una endianness in anticipo. Lo spazio per i metadati dovrebbe essere sempre nella versione 0 di un formato binario, altrimenti finirai con kludges orribili come ID3. Ho una grande simpatia per la logica delle specifiche PNG per quanto riguarda l'estensibilità tramite nuovi tipi di blocchi anziché i dossi della versione del formato. Tuttavia, i file strutturati in blocchi comportano una serie di complessità, quindi esito a raccomandarli per casi semplici. Sono stato tentato di raccomandare HDF come formato generico che ha già affrontato molti di questi problemi.
zwol,

2

Architetture diverse hanno rappresentazioni diverse per numeri interi. Il rischio principale qui è il salvataggio della rappresentazione in byte di un numero intero nella macchina A e quindi il tentativo di rileggerlo e interpretare il contenuto come numeri interi nella macchina B. Se le macchine A e B hanno dimensioni diverse per numeri interi e / o endianness differenti , " Molto probabilmente causerà comportamenti indefiniti (ad es. in C) o un'eccezione.

Dato che questo è solo un esempio di programmazione e non un programma "reale", non è proprio un problema. Se questo fosse un vero programma, girare il proprio formato binario specifico per l'applicazione di solito non è una buona idea; ci sono soluzioni migliori, come SQLite o formati di serializzazione basati su stringhe come JSON, YAML, XML, ecc. Per i singoli valori sarebbe sufficiente trasformarlo in una stringa; per elenchi semplici potresti salvare una stringa per riga e dividere semplicemente l'input su newline quando lo rileggi.


D'accordo in generale, ma JSON o XML aumenterebbero significativamente le dimensioni di un file contenente 10 ^ 7 numeri. Inoltre, vengono generalmente letti e analizzati tutti in una volta, ma il capitolo in questione si occupa dell'ordinamento dei file contenenti più dati di quanti si possano inserire nella memoria disponibile.
Caleb,

Dipende da cosa stai facendo. A volte l'hit di prestazioni di SQL vs un roll-your-own è importante. L'ultima volta che l'ho fatto ho avuto piccoli dischi e c'era un'alta probabilità che avrei voluto i vicini. La lettura di un blocco più grande dal disco in genere non costa quasi nulla, quindi se volessi un record leggevo 1000 in una cache. I miei dischi erano quasi sicuramente uno accanto all'altro, con SQL la testa del disco rimbalzava dappertutto.
Loren Pechtel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.