打开具有特定字(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看看行不行。