打开具有特定字(16 位)结构的特定文件
Open specific file with the specific words (16 bits) structure
我有特定的二进制文件?包含有关用于使用自定义相机拍照的配置数据的文件格式。此文件格式名为 DAI,包含 offset/gain/etc...
的示例值
我在 java 中使用 black-box 脚本将此文件转换为 .csv,我想在 Matlab 中执行相同的操作。我有一个配置文件,以 ascii 格式描述了该文件的构建方式(字段名称、数据类型、first_word、last_word、low_bit、high_bit ).例如,我知道 DAI 文件中的第一个字段是:
备用1;字符; first_word=0; low_bit=0; high_bit=7
但现在我不知道如何使用这些信息。我的第一个想法是 fopen() 文件并使用 fread() 从文件中读取二进制数据并将其转换为我想要的格式,但我不知道如何使用 "last_word,high_bit,..." 的值来做所以。我对二进制文件了解有限
总结一下:
file.dai 包含数据 /
file.cfg 包含结构 :
mband_1_start_line; PCHAR; first_word=12; low_bit=6; high_bit=15
mband_1_length; PCHAR; first_word=12; low_bit=0; high_bit=5
mband_1_gain; PCHAR; first_word=13; low_bit=0; high_bit=7
mband_1_offset; PCHAR; first_word=13; low_bit=8; last_word=14; high_bit=7
并且我想恢复与 mband_1_offset.
等字段对应的数据
如果有人能帮助我找出这样做的好方法,我将非常感激!
[编辑:已解决] 因此,感谢您非常有帮助的帮助,即使 header 发生变化,我也设法获取了每个字段的值!
这是最终代码:
这是最终代码:
...code to retrieve the content of the .cfg file....
%% Open and read the DAI file
fid = fopen(dai_file,'r','l');
% First thing is to skip the header
% We read a first time the file
dat=fread(fid,inf,'*uint8');
% We search for the position of the end of the header : NUL NUL ETX
% In decimal it gives :
skip = findstr(dat',[000,000,003]);
% We define the wordsize : 2 bytes (2 words)
wordsize = 2;
% We rewind the file to start over to get the values for each field
frewind(fid);
% We initiate the structure camdat containing the datas of the camera
camdat=struct;
% We start the loop for each field of the layout config file
for ct = 1:length(layout)
% Defining the words/bits
first_word = layout{ct,3};
last_word = layout{ct,5};
low_bit = layout{ct,4};
high_bit = layout{ct,6};
% We position to the "skip value + the position of the first_word in bytes"
fseek(fid,skip+first_word*wordsize,-1);
% We compute the number of words (last - first +1)
datasize=last_word-first_word+1;
% We read the datas as uint16 (words are 16bits)
data=fread(fid,datasize,'*uint16');
% We convert it to bits
% Case of 1 word
bits=bitget(data(1),[1:16]);
% Case of 2 words
if length(data) > 1
bits=[bits,bitget(data(2),1:16)];
high_bit = high_bit+16;
end
% We take only the bits that define the field (between low_bit and
% high_bit)
bits_used = bits(low_bit+1:high_bit+1);
% We convert the bits to dec
data = sum(bits_used.*uint16(2).^uint16([0:length(bits_used)-1]));
% We store it in the camdat.field struct
camdat.(layout{ct,1})=data;
end
% We close the DAI file
fclose(fid);
% Displaying for test
camdat
好的,您获得了有关文件布局的信息。
我会先以更易访问的格式存储它
layout{1,1} = 'mband_1_start_line';
layout{1,2} = 'PCHAR';
layout{1,3} = 12;
layout{1,4} = 6;
layout{1,5} = 12;
layout{1,6} = 15;
然后循环布局
wordsize = 2; %bytes / word
fid = fread(filename,'r','l')
camdat=struct;
for ct = 1:size(layout,1)
fseek(fid,-1,layout{1,3}/wordsize) %go to byte position
datsize=layout{1,5}-layout{1,3}+1; %number of words
data=fread(fid,datsize,'*uint16') %get words
bits=bitget(data(1),[1:16]); %convert to bits
for ct = 2:datasize
bits=[bits,bitget(data(ct),[1:16])];
end
bits = bits(layout{1,4}:(datasize-1)*16+layout{1,6};%get bits
data = sum(bits.*uint16(2).^uint16([0:(length(bits)-1)])) %convert back
camdat.(layout{1,1})=data; %store
end
fclose(fid)
超过16位的值当然会有问题。
如果字长不同,您可以将其更改为 4(对于 32 位)或 8(对于 64 位),但是您还必须在循环中更改它。
所以我一直在借助您的帮助来想办法做我想做的事。
这个想法是转到 "first_word" 的字节,取第一个和最后一个字之间的位(以及 low_bit 和 high_bit),将它们转换为小数。使用您的代码,我完成了以下给出的结果,但不是我一直在等待的结果(在 .csv 中)(attached file)。
首先,我不确定我是否处理好 last_word 与 first_word 不同的情况。
然后我不确定我的 fseek() 是否以文件的正确字节发送给我...
%% Name of the files
%% Open and read the .cfg file
%% Open and read the DAI file
...So here I've got my .cfg opened and store in layout{i,j}
wordsize = 2; %bytes / word
fid = fopen(dai_file,'r','l');
camdat=struct;
for ct = 1:length(layout)
first_word = layout{ct,3};
last_word = layout{ct,5};
low_bit = layout{ct,4};
high_bit = layout{ct,6};
fseek(fid,first_word*wordsize,-1); %go to bytes
datasize=last_word-first_word+1; %number of words
data=fread(fid,datasize,'*uint16'); %get words
bits=bitget(data(1),[1:16]); %convert to bits
if length(data) > 1 % case of 2 words
bits=[bits,bitget(data(2),1:16)];
high_bit = high_bit+16;
end
bits = bits(low_bit+1:high_bit+1);%get bits
data = sum(bits.*uint16(2).^uint16([0:length(bits)-1])); %convert back
camdat.(layout{ct,1})=data; %store
end
camdat
fclose(fid);
因此,如果您知道我哪里错了,我将不胜感激!!!!
在这种情况下,我的方法是找到与您的数据匹配的文件部分。
fid = fopen('dai_file.dai','r','l');
dat=fread(fid,inf,'*uint8');
findstr(dat',[74,210,129,93]);
>> 891 1159 1427 1695 ....
奇怪的是,这种情况发生了 100 次。
如果字节 891 是正确的,那么 bios_1 不在第 4 个字的第 0 到 7 位,而是在第 445 个字的第 0 到 7 位。
我们来试试
fid = fopen(dai_file,'r','l');
fseek(fid,445*2,-1)
data=fread(fid,1,'*uint16');
bits=bitget(data(1),[1:16]);
bits = bits(1:8);
data = sum(bits.*uint16(2).^uint16([0:7]))
>> data = 74
是的,就是这样。所以我建议给每一个词条加441看看行不行。
我有特定的二进制文件?包含有关用于使用自定义相机拍照的配置数据的文件格式。此文件格式名为 DAI,包含 offset/gain/etc...
的示例值我在 java 中使用 black-box 脚本将此文件转换为 .csv,我想在 Matlab 中执行相同的操作。我有一个配置文件,以 ascii 格式描述了该文件的构建方式(字段名称、数据类型、first_word、last_word、low_bit、high_bit ).例如,我知道 DAI 文件中的第一个字段是: 备用1;字符; first_word=0; low_bit=0; high_bit=7
但现在我不知道如何使用这些信息。我的第一个想法是 fopen() 文件并使用 fread() 从文件中读取二进制数据并将其转换为我想要的格式,但我不知道如何使用 "last_word,high_bit,..." 的值来做所以。我对二进制文件了解有限
总结一下:
file.dai 包含数据 / file.cfg 包含结构 :
mband_1_start_line; PCHAR; first_word=12; low_bit=6; high_bit=15
mband_1_length; PCHAR; first_word=12; low_bit=0; high_bit=5
mband_1_gain; PCHAR; first_word=13; low_bit=0; high_bit=7
mband_1_offset; PCHAR; first_word=13; low_bit=8; last_word=14; high_bit=7
并且我想恢复与 mband_1_offset.
等字段对应的数据如果有人能帮助我找出这样做的好方法,我将非常感激!
[编辑:已解决] 因此,感谢您非常有帮助的帮助,即使 header 发生变化,我也设法获取了每个字段的值! 这是最终代码:
这是最终代码:
...code to retrieve the content of the .cfg file....
%% Open and read the DAI file
fid = fopen(dai_file,'r','l');
% First thing is to skip the header
% We read a first time the file
dat=fread(fid,inf,'*uint8');
% We search for the position of the end of the header : NUL NUL ETX
% In decimal it gives :
skip = findstr(dat',[000,000,003]);
% We define the wordsize : 2 bytes (2 words)
wordsize = 2;
% We rewind the file to start over to get the values for each field
frewind(fid);
% We initiate the structure camdat containing the datas of the camera
camdat=struct;
% We start the loop for each field of the layout config file
for ct = 1:length(layout)
% Defining the words/bits
first_word = layout{ct,3};
last_word = layout{ct,5};
low_bit = layout{ct,4};
high_bit = layout{ct,6};
% We position to the "skip value + the position of the first_word in bytes"
fseek(fid,skip+first_word*wordsize,-1);
% We compute the number of words (last - first +1)
datasize=last_word-first_word+1;
% We read the datas as uint16 (words are 16bits)
data=fread(fid,datasize,'*uint16');
% We convert it to bits
% Case of 1 word
bits=bitget(data(1),[1:16]);
% Case of 2 words
if length(data) > 1
bits=[bits,bitget(data(2),1:16)];
high_bit = high_bit+16;
end
% We take only the bits that define the field (between low_bit and
% high_bit)
bits_used = bits(low_bit+1:high_bit+1);
% We convert the bits to dec
data = sum(bits_used.*uint16(2).^uint16([0:length(bits_used)-1]));
% We store it in the camdat.field struct
camdat.(layout{ct,1})=data;
end
% We close the DAI file
fclose(fid);
% Displaying for test
camdat
好的,您获得了有关文件布局的信息。
我会先以更易访问的格式存储它
layout{1,1} = 'mband_1_start_line';
layout{1,2} = 'PCHAR';
layout{1,3} = 12;
layout{1,4} = 6;
layout{1,5} = 12;
layout{1,6} = 15;
然后循环布局
wordsize = 2; %bytes / word
fid = fread(filename,'r','l')
camdat=struct;
for ct = 1:size(layout,1)
fseek(fid,-1,layout{1,3}/wordsize) %go to byte position
datsize=layout{1,5}-layout{1,3}+1; %number of words
data=fread(fid,datsize,'*uint16') %get words
bits=bitget(data(1),[1:16]); %convert to bits
for ct = 2:datasize
bits=[bits,bitget(data(ct),[1:16])];
end
bits = bits(layout{1,4}:(datasize-1)*16+layout{1,6};%get bits
data = sum(bits.*uint16(2).^uint16([0:(length(bits)-1)])) %convert back
camdat.(layout{1,1})=data; %store
end
fclose(fid)
超过16位的值当然会有问题。
如果字长不同,您可以将其更改为 4(对于 32 位)或 8(对于 64 位),但是您还必须在循环中更改它。
所以我一直在借助您的帮助来想办法做我想做的事。 这个想法是转到 "first_word" 的字节,取第一个和最后一个字之间的位(以及 low_bit 和 high_bit),将它们转换为小数。使用您的代码,我完成了以下给出的结果,但不是我一直在等待的结果(在 .csv 中)(attached file)。
首先,我不确定我是否处理好 last_word 与 first_word 不同的情况。
然后我不确定我的 fseek() 是否以文件的正确字节发送给我...
%% Name of the files
%% Open and read the .cfg file
%% Open and read the DAI file
...So here I've got my .cfg opened and store in layout{i,j}
wordsize = 2; %bytes / word
fid = fopen(dai_file,'r','l');
camdat=struct;
for ct = 1:length(layout)
first_word = layout{ct,3};
last_word = layout{ct,5};
low_bit = layout{ct,4};
high_bit = layout{ct,6};
fseek(fid,first_word*wordsize,-1); %go to bytes
datasize=last_word-first_word+1; %number of words
data=fread(fid,datasize,'*uint16'); %get words
bits=bitget(data(1),[1:16]); %convert to bits
if length(data) > 1 % case of 2 words
bits=[bits,bitget(data(2),1:16)];
high_bit = high_bit+16;
end
bits = bits(low_bit+1:high_bit+1);%get bits
data = sum(bits.*uint16(2).^uint16([0:length(bits)-1])); %convert back
camdat.(layout{ct,1})=data; %store
end
camdat
fclose(fid);
因此,如果您知道我哪里错了,我将不胜感激!!!!
在这种情况下,我的方法是找到与您的数据匹配的文件部分。
fid = fopen('dai_file.dai','r','l');
dat=fread(fid,inf,'*uint8');
findstr(dat',[74,210,129,93]);
>> 891 1159 1427 1695 ....
奇怪的是,这种情况发生了 100 次。
如果字节 891 是正确的,那么 bios_1 不在第 4 个字的第 0 到 7 位,而是在第 445 个字的第 0 到 7 位。
我们来试试
fid = fopen(dai_file,'r','l');
fseek(fid,445*2,-1)
data=fread(fid,1,'*uint16');
bits=bitget(data(1),[1:16]);
bits = bits(1:8);
data = sum(bits.*uint16(2).^uint16([0:7]))
>> data = 74
是的,就是这样。所以我建议给每一个词条加441看看行不行。