15

我对 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));
  • %08X和这些东西是怎么回事hex2dec
  • 另外,为什么要指定3*4而不是12?

真的,我想知道如何[A, count] = fread(fid, 3, 'uint32');在 Python 中复制,io.readline()就像拉文件的前 3 个字符一样。抱歉,如果我在这里的某个地方遗漏了要点。只是io.readline(3)在文件上使用似乎返回了它不应该返回的东西,而且我不明白block_length当它可能很长时它如何适合单个字节。

感谢您阅读本文。我希望你能理解我想知道的那种!(任何见解都值得赞赏。)

4

4 回答 4

20

用于读取一维数组的 Python 代码

在用 Python 替换 Matlab 时,我想将二进制数据读入 a 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 代码

Matlabfread能够将数据读入矩阵形式[m, n],而不仅仅是将其读入列向量。例如,要将数据读入具有 2 行的矩阵,请使用:

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

二维数组的等效 Python 代码

您可以使用 Numpyshapetranspose.

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。
于 2013-02-06T02:36:52.017 回答
8

从 的文档来看fread,它是一个读取二进制数据的函数。第二个参数指定输出向量的大小,第三个参数指定读取的项目的大小/类型。

为了在 Python 中重新创建它,您可以使用该array模块:

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

这将从文件中读取三个 uint32 值,这些值在之后f可用。a从以下文档fromfile

从文件对象 f 中读取 n 个项目(作为机器值)并将它们附加到数组的末尾。如果可用的项目少于 n 个,则会引发 EOFError,但可用的项目仍会插入到数组中。f 必须是真正的内置文件对象;其他带有 read() 方法的东西不会做。

数组实现了序列协议,因此支持与列表相同的操作,但您也可以使用该.tolist()方法从数组创建普通列表。

于 2010-01-27T10:44:25.530 回答
2

真的,我想知道如何复制[A, count] = fread(fid, 3, 'uint32');

在 Matlab 中,fread()的签名之一是fread(fileID, sizeA, precision). 这会读入sizeA文件的第一个元素(不是字节),每个元素的大小都足够precision. 在这种情况下,由于您正在读取uint32,因此每个元素的大小为 32 位或 4 个字节。

因此,尝试io.readline(12)从文件中获取前 3 个 4 字节元素。

于 2010-01-27T10:34:20.290 回答
0

Torsten 的回答涵盖了第一部分……无论如何,您将需要arraynumarray对这些数据做任何事情。

至于 %08X 和 hex2dec 的东西,%08X 只是那些 unit32 数字的打印格式(8 位十六进制,与 Python 完全相同),而 hex2dec('4D445254') 是 0x4D445254 的 matlab。

最后,matlab中的~=是按位比较;在 Python 中使用 ==。

于 2010-01-27T11:37:33.673 回答