15

我正在将 matlab 脚本转换为 numpy,但在从二进制文件中读取数据时遇到了一些问题。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');

谢谢!

4

4 回答 4

26

您可以以正常方式将 seek 与文件对象一起使用,然后在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]
于 2013-01-09T20:09:26.613 回答
3

可能有更好的答案......但是当我遇到这个问题时,我有一个文件,我已经想分别访问不同的部分,这给了我一个简单的解决这个问题的方法。

例如,chunkyfoo.bin一个文件由一个 6 字节的标头、一个 1024 字节的numpy数组和另一个 1024 字节的numpy数组组成。您不能只打开文件并寻找 6 个字节(因为首先要做的numpy.fromfilelseek回到 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,并且它会工作,而不会影响and 。readfmma1a2

我为不同的非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还可以选择将其保留为 anumpy.memmap而不是 a numpy.array,这样可以numpy更好地控制分页等/反馈。但实际上让 anumpy.memmap和 anmmap一起工作非常棘手。)

于 2013-01-09T19:56:13.583 回答
2

当我必须在异构二进制文件中任意读取时,我就是这样做的。
Numpy 允许通过更改数组的 dtype 以任意方式解释位模式。问题中的 Matlab 代码读取 achar和 two uint

阅读这篇论文(在用户级别上易于阅读,而不是为科学家阅读),了解通过更改数组的 dtype、stride、维度可以实现什么。

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]
于 2013-01-09T21:20:14.830 回答
1

有一个相当新的特点numpy.fromfile()

偏移

与文件当前位置的偏移量(以字节为单位)。默认为 0。仅允许用于二进制文件。

版本 1.17.0 中的新功能。

import numpy as np
import os

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

x = np.fromfile("temp", dtype=np.int32, offset=256)  # use the offset
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]
于 2020-08-03T10:07:17.510 回答