我使用以下方法从二进制文件中的任何给定偏移量读取二进制数据。我拥有的二进制文件很大,为10GB,因此我通常在需要时通过指定应从哪个偏移量start_read
读取多少字节以及从num_to_read
读取多少字节来读取它的一部分。我使用Python 3.6.4 :: Anaconda, Inc.
,平台Darwin-17.6.0-x86_64-i386-64bit
和os模块:
def read_from_disk(path, start_read, num_to_read, dim):
fd = os.open(path, os.O_RDONLY)
os.lseek(fd, start_read, 0) # Where to (start_read) from the beginning 0
raw_data = os.read(fd, num_to_read) # How many bytes to read
C = np.frombuffer(raw_data, dtype=np.int64).reshape(-1, dim).astype(np.int8)
os.close(fd)
return C
当要读取的数据块大约小于2GB时,此方法效果很好。当num_to_read > 2GG
时,出现此错误:
raw_data = os.read(fd, num_to_read) # How many to read (num_to_read)
OSError: [Errno 22] Invalid argument
我不确定为什么会出现此问题以及如何解决此问题。我们非常感谢您的帮助。
答案 0 :(得分:4)
os.read
function只是平台read
函数的薄包装。
在某些平台上,这是一个无符号或有符号的32位int, 1 ,这意味着在这些平台上一次可以read
进行一次访问的最大分别为4GB或2GB。
因此,如果您想阅读更多内容,并且想要跨平台,则必须编写代码来处理此问题,并缓冲多个read
。
这可能有点麻烦,但是您在这里故意使用最低级别的直接映射到OS-API。如果您不喜欢这样:
io
返回的file
模块对象(Python 3.x)或open
对象(2.7)。 mmap
(假设您使用的是64位平台)。在这里要做的正确的事几乎可以肯定是前两者的结合。在Python 3中,它看起来像这样:
with open(path, 'rb', buffering=0) as f:
f.seek(start_read)
count = num_to_read // 8 # how many int64s to read
return np.fromfile(f, dtype=np.int64, count=count).reshape(-1, dim).astype(np.int8)
1。对于Windows,POSIX仿真库的_read
函数使用int
作为count参数,该参数是32位带符号的。对于每个其他现代平台,请参阅POSIX read
,然后在您的平台上查找size_t
,ssize_t
和off_t
的定义。请注意,许多POSIX平台具有单独的64位类型和相应的功能,而不是将现有类型的含义更改为64位。 Python将使用标准类型,而不是特殊的64位类型。