os.read()给出OSError:[Errno 22]读取大数据时参数无效

时间:2018-06-22 22:26:42

标签: python python-3.x operating-system

我使用以下方法从二进制文件中的任何给定偏移量读取二进制数据。我拥有的二进制文件很大,为10GB,因此我通常在需要时通过指定应从哪个偏移量start_read读取多少字节以及从num_to_read读取多少字节来读取它的一部分。我使用Python 3.6.4 :: Anaconda, Inc.,平台Darwin-17.6.0-x86_64-i386-64bitos模块:

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

我不确定为什么会出现此问题以及如何解决此问题。我们非常感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

os.read function只是平台read函数的薄包装。

在某些平台上,这是一个无符号或有符号的32位int, 1 ,这意味着在这些平台上一次可以read进行一次访问的最大分别为4GB或2GB。

因此,如果您想阅读更多内容,并且想要跨平台,则必须编写代码来处理此问题,并缓冲多个read

这可能有点麻烦,但是您在这里故意使用最低级别的直接映射到OS-API。如果您不喜欢这样:

  • 使用io返回的file模块对象(Python 3.x)或open对象(2.7)。
  • 只需让NumPy读取文件,这将具有NumPy足够聪明的优势,而不必首先尝试一次将整个内容读取到内存中。
  • 或者,对于如此大的文件,您可能需要降低级别并使用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_tssize_toff_t的定义。请注意,许多POSIX平台具有单独的64位类型和相应的功能,而不是将现有类型的含义更改为64位。 Python将使用标准类型,而不是特殊的64位类型。