Как читать часть двоичного файла с numpy?

Я преобразовываю matlab script в numpy, но имею некоторые проблемы с чтением данных из двоичного файла. Есть ли equivelent to fseek при использовании fromfile, чтобы пропустить начало файла? Это тип экстракций, которые мне нужно сделать:

fid = fopen(fname);
fseek(fid, 8, 'bof');
second = fread(fid, 1, 'schar');
fseek(fid, 100, 'bof');
total_cycles = fread(fid, 1, 'uint32', 0, 'l');
start_cycle = fread(fid, 1, 'uint32', 0, 'l');

Спасибо!

Ответ 1

Вы можете использовать поиск с файловым объектом обычным способом, а затем использовать этот файл в fromfile. Вот полный пример:

import numpy as np
import os

data = np.arange(100, dtype=np.int)
data.tofile("temp")  # save the data

f = open("temp", "rb")  # reopen the file
f.seek(256, os.SEEK_SET)  # seek

x = np.fromfile(f, dtype=np.int)  # read the data into numpy
print x 
# [64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
# 89 90 91 92 93 94 95 96 97 98 99]

Ответ 2

Вероятно, лучший ответ... Но когда я столкнулся с этой проблемой, у меня был файл, который я уже хотел получить в разных частях отдельно, что дало мне легкое решение этой проблемы.

Например, скажем chunkyfoo.bin - это файл, состоящий из 6-байтового заголовка, массива размером 1024 байта numpy и еще одного 1024-байтового массива numpy. Вы не можете просто открыть файл и искать 6 байтов (потому что первая вещь numpy.fromfile делает это lseek назад к 0). Но вы можете просто mmap использовать этот файл и вместо него использовать fromstring:

with open('chunkyfoo.bin', 'rb') as f:
    with closing(mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ)) as m:
        a1 = np.fromstring(m[6:1030])
        a2 = np.fromstring(m[1030:])

Это похоже на то, что вы хотите сделать. Кроме того, конечно, что в реальной жизни смещение и длина до a1 и a2, вероятно, зависят от заголовка, а не от фиксированных комментариев.

Заголовок - это просто m[:6], и вы можете разобрать его, явно раздвинув его, используя модуль struct или что-нибудь еще, что вы сделали бы, выполнив read данные. Но, если вы предпочитаете, вы можете явно seek и read из f перед конструированием m, или после, или даже сделать те же вызовы на m, и он будет работать, не затрагивая a1 и a2.

Альтернативой, которую я сделал для другого проекта, не связанного с numpy, является создание объекта файла-обертки, например:

class SeekedFileWrapper(object):
    def __init__(self, fileobj):
        self.fileobj = fileobj
        self.offset = fileobj.tell()
    def seek(self, offset, whence=0):
        if whence == 0:
            offset += self.offset
        return self.fileobj.seek(offset, whence)
    # ... delegate everything else unchanged

Я сделал "делегировать все остальное без изменений", создав атрибут list атрибутов во время построения и используя это в __getattr__, но вы, вероятно, хотите что-то менее хакерское. numpy зависит только от нескольких методов файлового объекта, и я думаю, что они правильно документированы, поэтому просто делегируйте их. Но я думаю, что решение mmap имеет больше смысла здесь, если вы не пытаетесь механически переносить кучу явного кода seek. (Вы думаете, что mmap также предоставит вам возможность оставить его как numpy.memmap вместо numpy.array, что позволяет numpy иметь больше контроля над/обратную связь от поискового вызова и т.д. Но это на самом деле довольно сложно получить команды numpy.memmap и mmap для совместной работы.)

Ответ 3

Это то, что я делаю, когда мне приходится читать произвольное в гетерогенном двоичном файле.
Numpy позволяет интерпретировать битовый шаблон в режиме арбитража путем изменения dtype массива. Код Matlab в вопросе читает a char и два uint.

Прочтите эту статью (простое чтение на уровне пользователя, а не для ученых) о том, что можно достичь с изменением dtype, шага, размерности массив.

import numpy as np

data = np.arange(10, dtype=np.int)
data.tofile('f')

x = np.fromfile('f', dtype='u1')
print x.size
# 40

second = x[8]
print 'second', second
# second 2

total_cycles = x[8:12]
print 'total_cycles', total_cycles
total_cycles.dtype = np.dtype('u4')
print 'total_cycles', total_cycles
# total_cycles [2 0 0 0]       !endianness
# total_cycles [2]

start_cycle = x[12:16]
start_cycle.dtype = np.dtype('u4')
print 'start_cycle', start_cycle
# start_cycle [3]

x.dtype = np.dtype('u4')
print 'x', x
# x [0 1 2 3 4 5 6 7 8 9]

x[3] = 423 
print 'start_cycle', start_cycle
# start_cycle [423]