Frage

Ich entwerfe gerade eine Anwendung neu und bin auf ein Problem beim Serialisieren einiger Daten gestoßen.

Angenommen, ich habe ein Array der Größe mxn

double **data;

die ich in eine serialisieren möchte

char *dataSerialized

mit einfachen Trennzeichen (eines für Zeilen, eines für Elemente).

Die De-Serialisierung ist recht einfach, da Trennzeichen gezählt und die Größe für die zu speichernden Daten zugewiesen werden. Was ist jedoch mit der Serialisierungsfunktion, z. B. ?

serialize_matrix(double **data, int m, int n, char **dataSerialized);

Was wäre die beste Strategie, um die vom char-Array benötigte Größe zu bestimmen und den entsprechenden Speicher dafür zuzuweisen?

Verwenden Sie möglicherweise eine Exponentialdarstellung von Double in einer Zeichenfolge mit fester Breite? Ist es möglich, einfach alle Bytes von double in chars zu konvertieren und ein (doppelt) ausgerichtetes char-Array zu haben? Wie würde ich die Genauigkeit der Zahlen beibehalten?

HINWEIS:

Ich benötige die Daten in einem char-Array, nicht binär, nicht in einer Datei.

Die serialisierten Daten werden mithilfe von ZeroMQ zwischen einem C-Server und einem Java-Client über das Netzwerk gesendet. Wäre es angesichts der Array-Abmessungen und der Größe von (double) möglich, dass es zwischen diesen beiden immer genau rekonstruiert werden kann?

War es hilfreich?

Lösung

Java bietet eine ziemlich gute Unterstützung für das Lesen von Rohbytes und das Konvertieren in beliebige Bytes. Sie können sich für ein einfaches Drahtformat entscheiden und es dann in C serialisieren und in Java unserialisieren.

Hier ist ein Beispiel für ein extrem einfaches Format mit Code zum Unserialisieren und Serialisieren.

Ich habe ein etwas größeres Testprogramm geschrieben, das ich irgendwo ablegen kann, wenn Sie möchten.Es erstellt ein zufälliges Datenarray in C, serialisiert und schreibt die serialisierte Zeichenfolge base64-codiert in stdout.Das viel kleinere Java-Programm liest, decodiert und deserialisiert dies dann.

C-Code zum Serialisieren:

/* 
I'm using this format:
32 bit signed int                   32 bit signed int                   See below
[number of elements in outer array] [number of elements in inner array] [elements]

[elements] is buildt like
[element(0,0)][element(0,1)]...[element(0,y)][element(1,0)]...

each element is sendt like a 64 bit iee754 "double". If your C compiler/architecture is doing something different with its "double"'s, look forward to hours of fun :)

I'm using a couple non-standard functions for byte-swapping here, originally from a BSD, but present in glibc>=2.9.
*/

/* Calculate the bytes required to store a message of x*y doubles */
size_t calculate_size(size_t x, size_t y)
{
    /* The two dimensions in the array  - each in 32 bits - (2 * 4)*/
    size_t sz = 8;  
    /* a 64 bit IEE754 is by definition 8 bytes long :) */
    sz += ((x * y) * 8);    
    /* and a NUL */
    sz++;
    return sz;
}

/* Helpers */
static char* write_int32(int32_t, char*);
static char* write_double(double, char*);
/* Actual conversion. That wasn't so hard, was it? */
void convert_data(double** src, size_t x, size_t y, char* dst)
{

    dst = write_int32((int32_t) x, dst);    
    dst = write_int32((int32_t) y, dst);    

    for(int i = 0; i < x; i++) {
        for(int j = 0; j < y; j++) {
            dst = write_double(src[i][j], dst);
        }
    }
    *dst = '\0';
}


static char* write_int32(int32_t num,  char* c)
{
    char* byte; 
    int i = sizeof(int32_t); 
    /* Convert to network byte order */
    num = htobe32(num);
    byte = (char*) (&num);
    while(i--) {
        *c++ = *byte++;
    }
    return c;
}

static char* write_double(double d, char* c)
{
    /* Here I'm assuming your C programs use IEE754 'double' precision natively.
    If you don't, you should be able to convert into this format. A helper library most likely already exists for your platform.
    Note that IEE754 endianess isn't defined, but in practice, normal platforms use the same byte order as they do for integers.
*/
    char* byte; 
    int i = sizeof(uint64_t);
    uint64_t num = *((uint64_t*)&d);
    /* convert to network byte order */
    num = htobe64(num);
    byte = (char*) (&num);
    while(i--) {
        *c++ = *byte++; 
    }
    return c;
}

Java-Code zum Unserialisieren:

/* The raw char array from c is now read into the byte[] `bytes` in java */
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes));

int dim_x; int dim_y;
double[][] data;

try {   
    dim_x = stream.readInt();
    dim_y = stream.readInt();
    data = new double[dim_x][dim_y];
    for(int i = 0; i < dim_x; ++i) {
        for(int j = 0; j < dim_y; ++j) {
            data[i][j] = stream.readDouble();
        }
    }

    System.out.println("Client:");
    System.out.println("Dimensions: "+dim_x+" x "+dim_y);
    System.out.println("Data:");
    for(int i = 0; i < dim_x; ++i) {
        for(int j = 0; j < dim_y; ++j) {
            System.out.print(" "+data[i][j]);
        }
        System.out.println();
    }


} catch(IOException e) {
    System.err.println("Error reading input");
    System.err.println(e.getMessage());
    System.exit(1);
}

Andere Tipps

Wenn Sie eine Binärdatei schreiben, sollten Sie sich eine gute Möglichkeit überlegen, die tatsächlichen Binärdaten (64 Bit) Ihres doubles zu serialisieren.Dies könnte vom direkten Schreiben des Inhalts des Double in die Datei (unter Berücksichtigung der Endianität) bis zu einigen ausgefeilteren normalisierenden Serialisierungsschemata (z. B. mit einer genau definierten Darstellung von NaN) reichen.Das liegt wirklich an dir.Wenn Sie davon ausgehen, dass es sich im Wesentlichen um homogene Architekturen handelt, würde wahrscheinlich ein direkter Speicherauszug ausreichen.

Wenn Sie in eine Textdatei schreiben möchten und nach einer ASCII-Darstellung suchen, würde ich von einer numerischen Dezimaldarstellung dringend abraten.Stattdessen können Sie die 64-Bit-Rohdaten mit base64 oder ähnlichem in ASCII konvertieren.

Sie möchten wirklich die Präzision behalten, die Sie in Ihrem double haben!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top