Что эквивалентно 'fread' из Matlab в Python? - PullRequest
12 голосов
/ 27 января 2010

Я практически не знаю 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 ]

11 голосов
/ 06 февраля 2013

Python-код для чтения одномерного массива

При замене Matlab на Python я хотел прочитать двоичные данные в 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's shape и transpose.

import numpy as np

with open(inputfilename, 'rb') as fid:
    data_array = np.fromfile(fid, np.int16).reshape((-1, 2)).T
  • -1 говорит numpy.reshape выводить длину массива для этого измерения на основе другого измерения - эквивалент inf представления бесконечности Matlab
  • .T транспонирует массив так, чтобы он был двумерным массивом с первым измерением - осью - длиной 2.
7 голосов
/ 27 января 2010

Из документации 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:

Считать n элементов (как машинные значения) из файлового объекта f и добавить их в конец массива. Если доступно менее n элементов, вызывается EOFError, но доступные элементы по-прежнему вставляются в массив. f должен быть настоящим встроенным файловым объектом; что-то еще с методом read () не подойдет.

Массивы реализуют протокол последовательности и поэтому поддерживают те же операции, что и списки, но вы также можете использовать метод .tolist() для создания обычного списка из массива.

2 голосов
/ 27 января 2010

Правда, я хочу знать, как копировать [A, count] = fread(fid, 3, 'uint32');

В Matlab одна из fread() подписей fread(fileID, sizeA, precision). Это читает в первых sizeA элементах (не байтах) файла, каждый из которых имеет размер, достаточный для precision. В этом случае, поскольку вы читаете в uint32, каждый элемент имеет размер 32 бита или 4 байта.

Вместо этого попробуйте io.readline(12), чтобы получить первые 3 4-байтовых элемента из файла.

0 голосов
/ 27 января 2010

Первая часть покрыта ответом Торстена ... вам понадобится array или numarray, чтобы все равно что-нибудь сделать с этими данными.

Что касается% 08X и содержимого hex2dec,% 08X - это просто формат печати для этих номеров unit32 (шестнадцатеричное 8-значное число, точно такое же, как в Python), а hex2dec ('4D445254') - это matlab для 0x4D445254.

Наконец, ~ = в matlab - это побитовое сравнение; используйте == в Python.

...