Что такое "fread" от Matlab в Python?

Я практически не знаю 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 может вписываться в один байт, когда он может быть очень длинным.

Спасибо, что прочитал этот болтовню. Надеюсь, вы можете понять, что я хочу знать! (Любое понимание вообще ценится.)

Ответ 1

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

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

При замене Matlab на Python я хотел прочитать двоичные данные в numpy.array, поэтому я использовал numpy.fromfile, чтобы прочитать данные в 1-мерном массиве:

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], а не просто считывать ее в вектор-столбец. Например, для чтения данных в матрицу с двумя строками используйте:

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

Эквивалентный код Python для двумерного массива

Вы можете обрабатывать этот сценарий на Python, используя Numpy 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, чтобы указать длину массива для этого измерения на основе другого измерения - эквивалента представления бесконечности Matlab inf.
  • .T переносит массив так, чтобы он представлял собой двумерный массив с первым размером - ось - имела длину 2.

Ответ 3

Действительно, я хочу знать, как реплицировать [A, count] = fread(fid, 3, 'uint32');

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

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

Ответ 4

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

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

Наконец, ~ = в matlab - побитовое сравнение; use == в Python.