Python中'Matlab'的'fread'等效函数是什么?

16 投票
4 回答
31897 浏览
提问于 2025-04-15 18:32

我对Matlab几乎没有了解,现在需要把一些解析程序转成Python。这些程序是为了处理一些很大的文件,这些文件又被分成了“块”。我一开始就遇到了麻烦,特别是文件顶部的校验和部分。

在Matlab中,这到底是怎么回事呢?

status = fseek(fid, 0, 'cof');
fposition = ftell(fid);
disp(' ');
disp(['** Block ',num2str(iBlock),' File Position = ',int2str(fposition)]);

% ----------------- Block Start ------------------ %
[A, count] = fread(fid, 3, 'uint32');
if(count == 3)
    magic_l = A(1);
    magic_h = A(2);
    block_length = A(3);
else
    if(fposition == file_length)
        disp(['** End of file OK']);
    else
        disp(['** Cannot read block start magic !  Note File Length = ',num2str(file_length)]);
    end
    ok = 0;
    break;
end

fid是当前正在查看的文件,iBlock是一个计数器,用来表示你在文件中的哪个“块”。

magic_l和magic_h与后面的校验和有关,下面是相关的代码(直接跟在上面的代码后面):

disp(sprintf('  Magic_L = %08X, Magic_H = %08X, Length = %i', magic_l, magic_h, block_length));
correct_magic_l = hex2dec('4D445254');
correct_magic_h = hex2dec('43494741');

if(magic_l ~= correct_magic_l | magic_h ~= correct_magic_h)
    disp(['** Bad block start magic !']);
    ok = 0;
    return;
end

remaining_length = block_length - 3*4 - 3*4;   % We read Block Header, and we expect a footer
disp(sprintf('  Remaining Block bytes = %i', remaining_length));
  • %08Xhex2dec这些到底是干嘛的?
  • 为什么要用3*4而不是直接用12呢?

其实,我想知道怎么在Python中实现[A, count] = fread(fid, 3, 'uint32');,因为io.readline()只是读取文件的前3个字符。抱歉如果我在某些地方理解错了。使用io.readline(3)读取文件似乎返回了不该有的内容,我不明白block_length怎么能放在一个字节里,毕竟它可能非常长。

谢谢你读完这些乱七八糟的内容。我希望你能大概理解我想知道的是什么!(任何见解都非常感谢。)

4 个回答

3

其实我想知道怎么实现 [A, count] = fread(fid, 3, 'uint32');

在Matlab中,fread()的一个用法是 fread(fileID, sizeA, precision)。这个函数会从文件中读取前 sizeA 个元素(不是字节),每个元素的大小根据 precision 来决定。在这个例子中,由于你读取的是 uint32,所以每个元素的大小是32位,也就是4个字节。

所以,你可以试试用 io.readline(12) 来获取文件中的前3个4字节的元素。

21

用Python读取一维数组的代码

当我想用Python替代Matlab时,我需要把二进制数据读入一个numpy.array中,所以我使用了numpy.fromfile来读取数据到一个一维数组里:

import numpy as np

with open(inputfilename, 'rb') as fid:
    data_array = np.fromfile(fid, np.int16)

使用numpy.fromfile相比其他Python方法有一些好处,包括:

  • 不需要手动确定要读取多少个数据项。你可以通过count=这个参数来指定,但默认值是-1,这意味着会读取整个文件。
  • 可以指定一个打开的文件对象(就像我上面用的fid),或者你也可以直接指定一个文件名。我更喜欢使用打开的文件对象,但如果你想用文件名,可以把上面的两行替换成:

    data_array = numpy.fromfile(inputfilename, numpy.int16)
    

Matlab读取二维数组的代码

Matlab的fread可以把数据读取到一个形状为[m, n]的矩阵中,而不仅仅是读取到一个列向量中。例如,要把数据读取到一个有2行的矩阵,可以使用:

fid = fopen(inputfilename, 'r');
data_array = fread(fid, [2, inf], 'int16');
fclose(fid);

Python中对应的二维数组代码

在Python中,你可以使用Numpy的shapetranspose来处理这种情况。

import numpy as np

with open(inputfilename, 'rb') as fid:
    data_array = np.fromfile(fid, np.int16).reshape((-1, 2)).T
  • -1告诉numpy.reshape根据其他维度推断这个维度的数组长度,这和Matlab中的inf表示法是一样的。
  • .T会对数组进行转置,使得它变成一个二维数组,第一维(轴)的长度为2。
8

根据fread的文档,这个函数是用来读取二进制数据的。第二个参数指定了输出向量的大小,第三个参数则是读取的项目的大小或类型。

如果你想在Python中实现类似的功能,可以使用array模块:

f = open(...)
import array
a = array.array("L")  # L is the typecode for uint32
a.fromfile(f, 3)

这段代码会从文件f中读取三个uint32类型的值,读取到的值会存放在a中。根据fromfile的文档:

从文件对象f中读取n个项目(作为机器值),并将它们添加到数组的末尾。如果可用的项目少于n个,会抛出EOFError错误,但已经读取到的项目仍然会被插入到数组中。f必须是一个真正的内置文件对象;其他有read()方法的东西是无法使用的。

数组实现了序列协议,因此支持与列表相同的操作,但你也可以使用.tolist()方法将数组转换成普通的列表。

撰写回答