2009-03-18 11 views
6

Attualmente, sto salvando e caricando alcuni dati in strutture C/C++ in file usando fread()/fwrite(). Funziona bene quando si lavora all'interno di questa app C (posso ricompilare ogni volta che la struttura cambia per aggiornare gli argomenti sizeof() su fread()/fwrite()), ma come posso caricare questo file in altri programmi senza sapere in anticipo la sizeof() s della struttura C?Il modo migliore per serializzare una struttura C da deserializzare da Java, ecc.

In particolare, ho scritto questa altra app Java che visualizza i dati contenuti in quel file binario struct C, ma mi piacerebbe una soluzione generale su come leggere quel file binario. (Invece di dover inserire manualmente il sizeof() s nella sorgente dell'app Java ogni volta che la struttura C cambia ...)

Sto pensando di serializzare in un testo o XML di qualche tipo, ma io sono non so da che parte cominciare (come serializzare in C, poi come deserializzare in Java ed eventualmente in altri linguaggi in futuro), e se è consigliabile qui dove un membro della struct è un array float che può andare verso l'alto di ~ 50 MB in formato binario (e ho centinaia di questi file di dati da leggere e scrivere).

struttura

La C è semplice (non grave nidificazione o puntatore riferimenti) e si presenta come la seguente:

struct MyStructure { 
    char *title; 
    int id; 
    int param1; 
    int param2; 
    float *data; 
} 

La parte che possono cambiare di più sono gli interi param.

Quali sono le mie opzioni qui?

risposta

4

È possibile utilizzare il formato DataInput/DataOutput di Java che è well described in the javadoc.

+0

Un grande trucco con DataInput/DataOutput è che leggono/scrivono dati multi-byte in formato Big Endian. Questo vale anche per java.io.RandomAccessFile. Fortunatamente puoi usare java.io.ByteBuffer per leggere/scrivere in formato Little Endian. Puoi anche utilizzare .order (ByteOrder.LITTLE_ENDIAN) e .order (ByteOrder.BIG_ENDIAN) per passare da un formato all'altro di un flusso. – AlwaysLearning

0

Una possibilità è la creazione di piccoli file XML con titolo, ID, parametri, ecc. E quindi un riferimento (in base al nome del file) in cui sono contenuti i dati float. Supponendo che non vi sia nulla di speciale nei dati float e che Java e C stiano utilizzando lo stesso formato in virgola mobile, è possibile leggere il file con readFloat() di DataInputStream.

4

Se si dispone del controllo di entrambe le basi di codice, è necessario considerare l'utilizzo di Protocol Buffers.

+0

Concordato (ma poiché eseguo una versione C# di buffer di protocollo, potrei essere di parte). Per informazioni, la versione principale C (non C++) è, AFAIK, http://code.google.com/p/protobuf-c/ –

1

Se la struttura non sta per cambiare (molto) e i dati sono in un formato abbastanza coerente, è sufficiente scrivere i valori in un file CSV o in un altro formato normale.

Questo può essere letto facilmente in Java e non dovrete preoccuparvi di serializzare in XML. A volte andare semplice è la via più facile.

0

Mi piacciono le risposte CSV e "Protocol Buffers" (sebbene, a prima vista, la cosa del buffer di protocollo potrebbe essere molto simile a YAML per quanto ne so).

Se avete bisogno di record, serrato per grandi volumi di dati, si potrebbe considerare questo:

Creare un file di intestazione di testo che descrive la struttura del file corrente: dimensioni da record (tipi ????) e nomi dei campi/dimensioni. Leggi e analizza l'intestazione, quindi usa operazioni di I/O binario di basso livello per caricare i campi di ogni record, le proprietà degli oggetti, o qualsiasi altra cosa la chiamiamo quest'anno.

Questo ti dà la possibilità di cambiare la strucutre un po 'e farlo descrivere in modo automatico, pur consentendo di impacchettare un volume elevato in uno spazio più piccolo di quello consentito da XML.

TMTOWTDI, credo.

+1

Per informazioni, i buffer di protocollo sono uno standard aperto (creato da Google) per il pacchetto completo (binario), dati interoperabili. È * di livello basso, con efficienze aggiuntive come l'imballaggio base-128/lunghezza variante. Solo senza l'intestazione. –

3

Dai un'occhiata a JSON. http://www.json.org. Se vai da javascript è un grande aiuto. Non so quanto sia buono il supporto Java.

+0

A questo punto, il supporto Java è fortunatamente eccellente. – StaxMan

0

Se:

  • tuoi dati è essenzialmente una grande varietà di carri allegorici;
  • è possibile testare la procedura di scrittura/lettura in tutti gli ambienti probabili (= combinazioni di macchine/compilatore OS/C) su cui verrà eseguita ciascuna estremità;
  • prestazioni è importante.

quindi probabilmente continuerei a scrivere i dati da C nel modo che stai facendo (magari con una leggera modifica - vedi sotto) e trasformare il problema in come leggi quei dati da Java.

Per leggere i dati di nuovo da Java, utilizzare ByteBuffer. Essenzialmente, estrarre una lastra di byte dai dati, avvolgere un ByteBuffer e quindi utilizzare i metodi get(), getFloat(), getInt(), ecc. Il pacchetto NIO ha anche buffer "wrapper", ad es. FloatBuffer, che dai test che ho eseguito sembra essere circa 20% faster per la lettura di grandi numeri dello stesso tipo.

Ora, una cosa da fare attenzione è l'ordinamento dei byte. Da Java, devi chiamare l'ordine (ByteOrder.LITTLE _ ENDIAN) o ordinare (ByteOrder.BIG _ ENDIAN) sul tuo buffer prima di iniziare a leggere i dati. Per decidere quale usare, suggerirei che all'inizio del flusso si scriva un valore noto di 16 byte (ad esempio 255 = 0x00ff). Quindi da Java, estrai questi due byte e controlla l'ordine (0xff, 0x00 o 0x00, 0xff) per vedere se hai poco o grande endian.

Problemi correlati