繁体   English   中英

如何用numpy读取二进制文件的一部分?

[英]How to read part of binary file with numpy?

我正在将 matlab 脚本转换为 numpy,但是在从二进制文件读取数据时遇到了一些问题。 使用fromfile跳过文件开头时是否有fromfilefseek的内容? 这是我需要做的提取类型:

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');

谢谢!

您可以以正常方式对文件对象使用 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]

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

例如, 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:])

这听起来正是您想要做的。 当然,除了在现实生活中, a1a2的偏移量和长度可能取决于标题,而不是固定的注释。

标头只是m[:6] ,您可以通过显式将其分开、使用struct模块或read数据后执行的任何其他操作来解析它。 但是,如果您愿意,您可以在构造m之前或之后显式地从f seekread ,甚至可以对m进行相同的调用,它会起作用,而不会影响a1a2

我为另一个非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__使用它来完成“委托其他一切不变”,但你可能想要一些不那么hacky的东西。 numpy仅依赖于类文件对象的少数方法,我认为它们已被正确记录,因此只需明确委派这些方法即可。 但我认为mmap解决方案在这里更有意义,除非您试图机械地移植一堆基于显式seek的代码。 (您可能认为mmap还可以让您选择将其保留为numpy.memmap而不是numpy.array ,这让numpy可以更好地控制分页等/反馈等。但实际上很难获得numpy.memmapmmap一起工作。)

当我必须在异构二进制文件中任意读取时,这就是我所做的。
numpy的允许通过改变来解释任意波形方式的比特模式D型阵列的。 问题中的 Matlab 代码读取一个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]

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

偏移INT

与文件当前位置的偏移量(以字节为单位)。 默认为 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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM