MATLAB 读取到二进制文件的末尾



我认为对于具有一些 MATLAB 专业知识的人来说,解决方案将非常简单,但我不知道该怎么做。

有一个二进制文件,我正在读取fread,我正在读取该文件的前 4 个字节,然后是接下来的 2 个字节。

我基本上想要这个读取 4 个字节然后重复 2 个字节直到文件末尾的过程。

所以读取的字节数是4,2,4,2,4,2......

我有以下内容来读取第一对数据,我希望重复此操作。

fileID = fopen('MyBinaryFile');
4bytes = fread(fileID, 4);
fseek(fileID, 4, 0);
2bytes = fread(fileID, 2);

提前感谢您的任何帮助和建议

我认为这是您之前的问题 MATLAB 读取混合数据类型二进制文件的变体。

您的目标是读取包含混合数据类型的二进制文件。在您的情况下,它包含 2 列:
1x single值(4 个字节(和 1x int16 个值(2 个字节(。

有几种方法可以读取此类文件。它们在速度上有所不同,因为某些方法可以最大程度地减少磁盘访问,但需要更多的临时内存,而其他方法仅使用所需的内存,但需要更多的磁盘访问(=较慢(。

最终,我将向您展示的 3 种方式会产生完全相同的结果

这个问题的直接答案是下面的版本#3,但我鼓励你看看这里描述的其他两个选项,它们都非常值得理解。


出于示例的目的,我必须按照您的描述创建一个二进制文件。这是这样完成的:

%% // write example file
A = single(linspace(-3,1,11)) ;  %// a few "float" (=single) data
B = int16(-5:5) ;                %// a few "int16" data
fileID = fopen('testmixeddata.bin','w');
for il=1:11
    fwrite(fileID,A(il),'single');   
    fwrite(fileID,B(il),'int16');   
end
fclose(fileID);

这将创建一个 2 列二进制文件,列为:

  • 11 个 float 类型的值从 -3 到 1。
  • 11 个 int16 类型的值,从 -5 到 +5。

供将来参考:

>> disp(A)
   -3.0000   -2.6000   -2.2000   -1.8000   -1.4000   -1.0000   -0.6000   -0.2000    0.2000    0.6000    1.0000
>> disp(B)
     -5     -4     -3     -2     -1      0      1      2      3      4      5

在下面的每个解决方案中,第一列将在名为 varSingle 的变量中读取,第二列将在名为 varInt16 的变量中读取。


1(一次性读取所有数据 - 之后转换为正确的类型

%% // SOLUTION 1 (fastest) : Read all data in one go - convert to proper type after
fileID = fopen('testmixeddata.bin');
R = fread(fileID,'uint8=>uint8') ;       %// read all values, most basic data type (unsigned 8 bit integer)
fclose(fileID);
colSize = [4 2] ; %// number of byte for each column [4 byte single, 2 byte int16]
R = reshape( R , sum(colSize) , [] ) ;          %// reshape data into a matrix (6 is because 4+2byte=6 byte per column)
temp = R(1:4,:) ;                               %// extract data for first column into temporary variable (OPTIONAL)
varSingle = typecast( temp(:) , 'single' ) ;    %// convert into "single/float"
temp = R(5:end,:) ;                             %// extract data for second column
varInt16  = typecast( temp(:) , 'int16' ) ;     %// convert into "int16"

这是我最喜欢的方法。特别是为了速度,因为它最大限度地减少了磁盘上的读/寻操作,并且大多数后计算都是在内存中完成的(比磁盘操作快得多(。

请注意,我使用的临时变量只是为了清晰/冗长,如果您正确索引原始数据,则可以完全避免它。

要了解的关键是typecast函数的使用。好消息是,自2014年以来,它变得更快b。


2( 逐列读取(使用"skipvalue"( - 2 遍方法

%% // SOLUTION 2 : Read column by column (using "skipvalue") - 2 pass approach
col1size = 4 ;                                  %// size of data in column 1 (in [byte])
col2size = 2 ;                                  %// size of data in column 2 (in [byte])
fileID    = fopen('testmixeddata.bin');
varSingle = fread(fileID,'*single',col2size) ;  %// read all "float" values, skipping all "int16" 
fseek(fileID,col1size,'bof') ;                  %// rewind to beginning of column 2 at the top of the file
varInt16  = fread(fileID,'*int16',col1size) ;   %// read all "int16" values, skipping all "float" 
fclose(fileID);

那也行得通。它工作正常...但它会比上面的方法 1 慢,因为您必须扫描文件两次。如果文件非常大,并且上面的方法 1 由于out of memory错误而失败,这可能是一个不错的选择。


3( 逐个元素读取

%% // SOLUTION 3 : Read element by element (slow - not recommended)
fileID = fopen('testmixeddata.bin');
varSingle=[];varInt16=[];
while ~feof(fileID)
    try
        varSingle(end+1) = fread(fileID, 1, '*single' ) ;
        varInt16(end+1)  = fread(fileID, 1, '*int16'  ) ;
    catch
        disp('reached End Of File')
    end
end
fclose(fileID);

这也确实有效,如果您正在编写C代码,那就太好了。但是在 Matlab 中,这不是推荐的方式(您的最终选择(


正如所承诺的,上面的 3 种方法将为您提供我们在开头文件中编写的内容:

>> disp(varSingle)
   -3.0000   -2.6000   -2.2000   -1.8000   -1.4000   -1.0000   -0.6000   -0.2000    0.2000    0.6000    1.0000
>> disp(varInt16)
    -5    -4    -3    -2    -1     0     1     2     3     4     5
fileID = fopen('MyBinaryFile');
kk=1;
while ~feof(fileID)
   bytes4(kk) = fread(fileID, 4);
   fseek(fileID, 4, 0);
   bytes2(kk) = fread(fileID, 2);
   kk=kk+1;
end

while循环条件是 ~feof ,代表文件结束。因此,只要您还没有到达文件的末尾,它就会运行。

我添加了kk,以便您存储所有内容,而不仅仅是在每次循环迭代时覆盖它们。

如果你想

在没有循环的情况下获取数据,有MATLABish的方法:

    %'Sizes'
    T = 4;    %'Time record size'
    D = 2;    %'Date record size'
    R = T+D;  %'Record size'
    %'Open file'
    f = fopen('MyBinaryFile', 'rb');
    if f < 0
            error('Could not open file.');
    end;
    %'Read the entire file at once, and close file'
    buf = fread(f, Inf, '*uint8');
    fclose(f);
    %'Ignore the last unpadded bytes, and reshape by the size of 1 record'
    buf = reshape(buf(1:R*fix(numel(buf)/R)), R, []);
    %'Pinpoint the data'
    time_bytes = buf(  1:  T, :);
    date_bytes = buf(T+1:T+D, :);

相关内容

  • 没有找到相关文章

最新更新