Foros del Web » Programación para mayores de 30 ;) » C/C++ »

A vueltas con un archivo binario

Estas en el tema de A vueltas con un archivo binario en el foro de C/C++ en Foros del Web. Hola a todos/as Tengo un pequeño problema que no consigo resolver, a ver si podeis echarme una mano. Tengo un archivo binario, compuesto por una ...
  #1 (permalink)  
Antiguo 12/11/2013, 04:50
 
Fecha de Ingreso: diciembre-2010
Mensajes: 6
Antigüedad: 13 años, 4 meses
Puntos: 0
Pregunta A vueltas con un archivo binario

Hola a todos/as

Tengo un pequeño problema que no consigo resolver, a ver si podeis echarme una mano.

Tengo un archivo binario, compuesto por una serie de "records" cada uno de ello de 21 bytes.
Cada uno de estos records, tiene varios campos de distintas longuitudes y distintos tipos (WORD, REAL y BYTE)

Conozco la estructura completa del record.

Si utilizo la instruccion "hexdump -v" de linux me sale lo siguiente:

0000000 0834 e134 b5e9 bdda 4142 d601 0e00 006a
0000010 0000 7780 3416 4108 0538 dab6 42bd 0141
0000020 01a7 80c0 0000 8000 0000 0834 d3b5 b649
0000030 bdda 4142 3401 f001 0069 0000 1280 3415
0000040 b108 5935 dab6 42bd 0141 016d 6b08 0000
0000050 8000 157e 0834 bff4 b712 bdda 4142 dc01
0000060 5a01 0023 0000 0080 3400 7c08 c659 dab7
0000070 42bd 0141 008a 6f86 0000 8000 0000 0834
0000080 ff60 b841 bdda 4142 ae01 1000 0022 0000
0000090 3980 340c 7008 9a10 dab8 42bd 0141 0253
00000a0 2440 0000 8000 0000 0834 9861 b8d7 bdda
00000b0 4142 7f01 0600 0081 0000 6680 340a ce08
00000c0 8c57 dab9 42bd 0141 0112 6fae 0000 8000
00000d0 0000 0834 a47e b9cf bdda 4142 e701 5e00
00000e0 0038 0000 1080 340d 4508 e841 dab9 42bd
00000f0 0141 017b 227e 0000 8000 0000 0834 8f31
0000100 ba03 bdda 4142 f001 2800 007d 0000 0080
0000110 3400 db08 2566 daba 42bd 0141 0081 2256
0000120 0000 8000 0000 0834 03ca ba39 bdda 4142
0000130 ac01 b000 0022 0000 0080 3400 7108 6978
0000140 daba 42bd 0141 00d6 384a 0000 8000 0894


Adjunto descripción de los datos.



Bien, según esto.... que tengo que hacer para traducir esos valores en hexadecimal a un tipo legible ???

Gracias de antemano por vuestra ayuda.

Edito: El archivo en cuestion es del día 28 de Julio de 2013, por si es relevante la información para sacar la fecha.

Última edición por urkitarke; 12/11/2013 a las 05:47 Razón: Complementar datos
  #2 (permalink)  
Antiguo 12/11/2013, 12:02
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: A vueltas con un archivo binario

Pues eso, lo que te indica la descripcion: primero te saltas los 2 bytes que no tienen significado, luego lees 8, luego saltas 1, luego lees 2, etc...

Por orden, primero abres el archivo:

Código C:
Ver original
  1. FILE *arx;
  2. if(!(arx = fopen(path, "rb"))) {
  3.     //error de acceso
  4. }

Ahora saltas 2 bytes:

Código C:
Ver original
  1. fseek(arx, 2L, SEEK_CUR);

Lees 8 bytes:

Código C:
Ver original
  1. //necesitas declarar el double
  2. double julian_date;
  3. fread(&julian_date, sizeof(double), 1, arx);

Saltas otro byte:

Código C:
Ver original
  1. fseek(arx, 1L, SEEK_CUR);

Lees la amplitud:

Código C:
Ver original
  1. //necesitas declarar el short
  2. short int amplitude;
  3. fread(&amplitude, sizeof(short int), 1, arx);

Y asi vas leyendo hasta terminar el primer record; luego haces lo mismo para el segundo. Ten en cuenta que para cada lectura tienes que hacer las comprovaciones de error necesarias, incluso por si el archivo estuviera mal escrito y terminara antes de tiempo.

Alternativamente está la forma serializada que consiste en guardar los tipos en una estructura y leer estructuras enteras, p.ej.:

Código C:
Ver original
  1. struct RECORD {
  2.     char internal_a[2];
  3.     double julian_time;
  4.     char internal_b;
  5.     short int amplitude;
  6.     etc...
  7. };

Solo te pongo los primeros pero ya ves de que va la cosa. Ahora en vez de leer campo por campo puedes leer toda la estructura:

Código C:
Ver original
  1. //necesitas declarar una estructura
  2. struct RECORD record;
  3. //reseteas los campos
  4. memset(&record, 0, sizeof(struct RECORD));
  5. //y lees el record
  6. fread(&record, sizeof(struct RECORD), 1, arx);

De esta forma en una sola lectura recuperas todo un record.

Lo siguiente es saber cuantos recors contiene el archivo. Sabiendo lo que ocupan todos los tipos, es decir sabiendo lo que ocupa la estructura RECORD, solo tienes que dividir el tamaño del archivo por el tamaño del record, tienes que obtener un numero entero, de lo contrario el archivo está mal construido. Primero recuperas el tamaño:

Código C:
Ver original
  1. size_t file_size;
  2. fseek(arx, 0L, SEEK_END);
  3. file_size = ftell(arx);
  4. fseek(arx, 0L, SEEK_SET);

Luego lo divides por el tamaño de la estructura:

Código C:
Ver original
  1. int n_records = file_size / sizeof(struct RECORD);

Ahora ya sabes cuantos records has de leer.

Y si quieres implementar los tipos indicados en la referencia solo tienes que redefinir los tipos que te comenté como los tipos indicados:

Código C:
Ver original
  1. typedef char BYTE;
  2. typedef short int WORD;
  3. typedef double REAL;

De esta forma puedes reescribir la estructura con los tipos redefinidos:

Código C:
Ver original
  1. struct RECORD {
  2.     BYTE internal_a[2];
  3.     REAL julian_time;
  4.     BYTE internal_b;
  5.     WORD amplitude;
  6.     etc...
  7. };

Saludos
vosk
  #3 (permalink)  
Antiguo 13/11/2013, 02:39
 
Fecha de Ingreso: diciembre-2010
Mensajes: 6
Antigüedad: 13 años, 4 meses
Puntos: 0
Respuesta: A vueltas con un archivo binario

joer

Muchas gracias por tu gran respuesta vosk, me he quedado impresionado

Me pongo manos a la obra !!!!

Ya te comento los resultados.

Gracias !!
  #4 (permalink)  
Antiguo 18/11/2013, 09:44
 
Fecha de Ingreso: diciembre-2010
Mensajes: 6
Antigüedad: 13 años, 4 meses
Puntos: 0
Respuesta: A vueltas con un archivo binario

Hola de nuevo....

He realizado el script conforme las instrucciones pero... algo debo hacer mal pues me slaen datos incoherentes.


Cita:
#include <conio.h>
#include <stdio.h>
#include <string.h>

struct RECORD{
short int id;
double julian_time;
char internal_b;
short int amplitude;
short int bearing;
short int wave;
char polarity;
char stroke;
short int range;
};

int main() {

double julian_date;
short int id,amplitude,bearing,wave,range;
char internal_b,polarity,stroke;

FILE *arx;
if(!(arx = fopen("./prueba2.txt","rb"))) {
printf("No existe el archivo");
}
struct RECORD record;
memset(&record, 0, sizeof(struct RECORD));
fread(&record, sizeof(struct RECORD), 1, arx);

size_t file_size;
fseek(arx, 0L, SEEK_END);
file_size = ftell(arx);
fseek(arx, 0L, SEEK_SET);
int n_records = file_size / sizeof(struct RECORD);

printf("tenemos %i registros\n",n_records);

int i =1;

while(!feof(arx)){

printf("reg. num %d\n",i);
fread(&id,sizeof(short int),1,arx);
fread(&julian_date,sizeof(double),1,arx);
fread(&internal_b,sizeof(char),1,arx);
fread(&amplitude,sizeof(short int),1,arx);
fread(&bearing,sizeof(short int),1,arx);
fread(&wave,sizeof(short int),1,arx);
fread(&polarity,sizeof(char),1,arx);
fread(&stroke,sizeof(char),1,arx);
fread(&range,sizeof(short int),1,arx);

printf("Internal1: %d\nTime: %g\nInternal2: %c\nAmpli: %d\nBearin: %d\nWave: %d\nPolaridad: %c\nStroke: %c\nRange: %d\n==================\n",id,julian_date,internal_ b, amplitude, bearing, wave, polarity, stroke, range);

i++;

}
}
He cambiado el archivo de origen quitando los priemros dígitos y/o quitando espacios en blanco y/o quitando saltos de línea, quedándome el archivo del siguiente modo:

Cita:
0834e134b5e9bdda4142d6010e00006a000077803416410805 38dab642bd014101a780c00000800000000834d3b5b649bdda 41423401f0010069000012803415b1085935dab642bd014101 6d6b0800008000157e0834bff4b712bdda4142dc015a010023 0000008034007c08c659dab742bd0141008a6f860000800000 000834ff60b841bdda4142ae011000002200003980340c7008 9a10dab842bd01410253244000008000000008349861b8d7bd da41427f010600008100006680340ace088c57dab942bd0141 01126fae0000800000000834a47eb9cfbdda4142e7015e0000 3800001080340d4508e841dab942bd0141017b227e00008000 000008348f31ba03bdda4142f0012800007d000000803400db 082566daba42bd014100812256000080000000083403caba39 bdda4142ac01b000002200000080340071086978daba42bd01 4100d6384a000080000894083450f0ba6dbdda4142a001b200 00660000008034000e0879b9daba42bd0141008526a2000080 000000
y también así:

Cita:
0834e134b5e9bdda4142d6010e00006a000077803416410805 38dab642bd014101a780c0000080000000
0834d3b5b649bdda41423401f0010069000012803415b10859 35dab642bd0141016d6b0800008000157e
0834bff4b712bdda4142dc015a0100230000008034007c08c6 59dab742bd0141008a6f86000080000000
0834ff60b841bdda4142ae011000002200003980340c70089a 10dab842bd014102532440000080000000
08349861b8d7bdda41427f010600008100006680340ace088c 57dab942bd014101126fae000080000000
0834a47eb9cfbdda4142e7015e00003800001080340d4508e8 41dab942bd0141017b227e000080000000
08348f31ba03bdda4142f0012800007d000000803400db0825 66daba42bd014100812256000080000000
083403caba39bdda4142ac01b0000022000000803400710869 78daba42bd014100d6384a000080000894
083450f0ba6dbdda4142a001b20000660000008034000e0879 b9daba42bd0141008526a2000080000000
pero los datos que me devuelve el script son erróneos:

Cita:
tenemos 1204 registros


reg. num 1
Internal1: 14384
Time: 1.52046e-51
Internal2: e
Ampli: 25145
Bearin: 25700
Wave: 13409
Polaridad: 1
Stroke: 4
Range: 25650
==================
reg. num 2
Internal1: 12342
Time: 1.10764e-47
Internal2: a
Ampli: 12336
Bearin: 12336
Wave: 14135
Polaridad: 8
Stroke: 0
Range: 13363
==================
reg. num 3
Internal1: 13873
Time: 5.64466e-38
Internal2: d
Ampli: 25185
Bearin: 13366
Wave: 25138
Polaridad: d
Stroke: 0
Range: 13361
==================
reg. num 4
Internal1: 12337
Time: 1.41525e-76
Internal2: 0
Ampli: 12336
Bearin: 12344
Wave: 12336
Polaridad: 0
Stroke: 0
Range: 12336
==================

El campo "Time" debería ser el 28 de julio de 2013 que es cuando se tomaron los datos y ese dato que aparece, pasándolo a fecha gregoriana, no existe como tal.

Alguien podría decirme que estoy haciendo mal??
Podríais ayudarme??

Gracias.

PD: No he puesto todos los valores, sólo unos pocos de muestra.

Última edición por urkitarke; 18/11/2013 a las 09:55 Razón: Se guardó antes de tiempo :(
  #5 (permalink)  
Antiguo 18/11/2013, 13:59
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: A vueltas con un archivo binario

"...He cambiado el archivo de origen quitando los priemros dígitos y/o quitando espacios en blanco y/o quitando saltos de línea..."

Un momento: el archivo es de texto tal cual lo tienes ahí? Es decir que es de texto plano? O se generó en modo binario?

En mi post anterior estaba suponiendo que trabajas sobre un archivo binario (sin entrar en detalles de si todos los archivos son binarios). Si no es así la serializacion que te comenté no funciona, pero la lectura directa tampoco porque ambos metodos se basan en lectura y asignacion binaria.

Una cosa, en tu codigo haces lo siguiente (en este orden): lees un record como estructura, luego determinas el nº de records, y luego vas leyendo campos individuales hasta el final del archivo. Lo ideal es (en este orden): determinar el nº de records y luego hacer un bucle para ese numero de records leyendolos como structs (para cada lectura un control de feof, por si estuviese mal construido). Pero si el archivo no es binario esto no funciona, y si el archivo es binario y lo modificas a mano en modo texto tampoco.

Saludos
vosk
  #6 (permalink)  
Antiguo 19/11/2013, 02:34
 
Fecha de Ingreso: diciembre-2010
Mensajes: 6
Antigüedad: 13 años, 4 meses
Puntos: 0
Respuesta: A vueltas con un archivo binario

Hola vosk

Cita:
Un momento: el archivo es de texto tal cual lo tienes ahí? Es decir que es de texto plano? O se generó en modo binario?
Si, el archivo original es binario ->http://webs.ono.com/mod/20130728.ldc


y yo lo pasé a texto pensando que se podría trabajar mejor ..pero ya veo que fue un error.

Vuelvo a ponerme con tus recomendaciones y te cuento mis... avances.

Gracias de nuevo

Etiquetas: binario, struct
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 22:17.