2009-03-18 7 views
6

Actualmente, estoy guardando y cargando algunos datos en estructuras C/C++ a archivos usando fread()/fwrite(). Esto funciona bien cuando se trabaja con esta única aplicación C (puedo recompilar cada vez que la estructura cambia para actualizar los argumentos de sizeof() a fread()/fwrite()), pero ¿cómo puedo cargar este archivo en otros programas sin saber de antemano? el tamaño de() s de la C struct?La mejor manera de serializar una estructura C para ser deserializada por Java, etc.

En particular, he escrito esta otra aplicación Java que visualiza los datos contenidos en ese archivo binario C struct, pero me gustaría una solución general sobre cómo leer ese archivo binario. (En lugar de tener que poner manualmente el tamaño de() s en la fuente de la aplicación Java cada vez que cambia la estructura C ...)

Estoy pensando en serializar texto o XML de algún tipo, pero estoy no estoy seguro de por dónde empezar (cómo serializar en C, cómo deserializar en Java y posiblemente en otros idiomas en el futuro), y si es aconsejable aquí, donde un miembro de la estructura es una matriz flotante que puede ir más allá de ~ 50 MB en formato binario (y tengo cientos de estos archivos de datos para leer y escribir).

estructura

El C es simple (no grave de anidación o puntero referencias) y tiene el siguiente aspecto:

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

La parte que son susceptibles de cambiar la mayoría son los enteros param.

¿Cuáles son mis opciones aquí?

Respuesta

4

Puede utilizar el formato DataInput/DataOutput de Java que es well described in the javadoc.

+0

Un gran problema con DataInput/DataOutput es que leen/escriben datos de múltiples bytes en formato Big Endian. Esto también se aplica a java.io.RandomAccessFile. Afortunadamente puede usar java.io.ByteBuffer para leer/escribir en formato Little Endian. Incluso puede usar .order (ByteOrder.LITTLE_ENDIAN) y .order (ByteOrder.BIG_ENDIAN) para intercambiar entre formatos a lo largo de una secuencia. – AlwaysLearning

0

Una posibilidad es crear pequeños archivos XML con título, ID, params, etc., y luego una referencia (por nombre de archivo) a donde están contenidos los datos float. Suponiendo que no hay nada de especial en los datos flotantes, y que Java y C utilizan el mismo formato de punto flotante, puede leer ese archivo con readFloat() de DataInputStream.

4

Si tiene el control de ambas bases de código, debe considerar el uso de Protocol Buffers.

+0

De acuerdo (pero dado que ejecuto una versión C# de buffer de protocolo, podría ser parcial). Para obtener información, la versión principal de C (no de C++) es, AFAIK, http://code.google.com/p/protobuf-c/ –

1

Si su estructura no va a cambiar (mucho), y sus datos están en un formato bastante uniforme, puede simplemente escribir los valores en un archivo CSV, o algún otro formato simple.

Esto se puede leer fácilmente en Java, y no tendrá que preocuparse por la serialización a XML. A veces ir simple es la ruta más fácil.

0

Me gustan las respuestas CSV y "Protocol Buffers" (aunque, a simple vista, el buffer de protocolo podría ser muy similar a YAML por lo que sé).

Si necesita registros apretadas para grandes volúmenes de datos, es posible que considere esto:

Crear un encabezado de archivo de texto que describe la estructura del archivo actual: tamaños de registro (????) tipos y nombres de campo/tamaños. Lea y analice el encabezado, luego use operaciones de E/S binarias de bajo nivel para cargar los campos de cada registro, er, las propiedades del objeto o como lo llamemos este año.

Esto le da la capacidad de cambiar un poco la estructura y hacer que sea autodescriptiva, al mismo tiempo que le permite empacar un volumen alto en un espacio más pequeño de lo que permitiría XML.

TMTOWTDI, supongo.

+1

. Para información, los búferes de protocolo son un estándar abierto (creado por Google) para paquetes ajustados (binario), datos interoperables. It * is * low level, con eficiencias adicionales como base-128/variant-length packing. Solo sin el encabezado. –

3

Eche un vistazo a JSON. http://www.json.org. Si vas desde javascript es una gran ayuda. Sin embargo, no sé lo bueno que es el soporte de Java.

+0

En este punto, el soporte de Java es afortunadamente excelente. – StaxMan

0

Si:

  • sus datos es esencialmente una gran variedad de flotadores;
  • puede probar el procedimiento de escritura/lectura en todos los entornos probables (= combinaciones de máquinas/compilador de sistema operativo/C) en los que se ejecutará cada extremo;
  • el rendimiento es importante.

entonces probablemente seguiría escribiendo los datos de C en la forma en que lo está haciendo (tal vez con una pequeña modificación - ver más abajo) y convertiré el problema en cómo leer esos datos de Java.

Para leer los datos de Java, utilice un ByteBuffer. Esencialmente, extrae losas de bytes de tus datos, envuelve un ByteBuffer alrededor de ellos, y luego usa los métodos get(), getFloat(), getInt() etc. El paquete NIO también tiene búferes de "envoltura", p. FloatBuffer, que de las pruebas que he hecho parece ser de aproximadamente 20% faster para leer grandes cantidades del mismo tipo.

Ahora, una cosa que tendrá que tener cuidado es el orden de bytes. Desde Java, debe llamar al orden (ByteOrder.LITTLE _ ENDIAN) u ordenar (ByteOrder.BIG _ ENDIAN) en su búfer antes de comenzar a leer los datos. Para decidir cuál usar, recomiendo que al comienzo de la transmisión escriba un valor conocido de 16 bytes (por ejemplo, 255 = 0x00ff). Luego, desde Java, extraiga estos dos bytes y verifique el orden (0xff, 0x00 o 0x00, 0xff) para ver si tiene endian pequeño o grande.

Cuestiones relacionadas