【问题标题】:"OSError: [Errno 22] Invalid argument" when read()ing a huge file“OSError:[Errno 22] Invalid argument”读取()大文件时
【发布时间】:2018-06-15 19:24:38
【问题描述】:

我正在尝试编写一个打印文件校验和的小脚本(使用来自https://gist.github.com/Zireael-N/ed36997fd1a967d78cb2 的一些代码):

import sys
import os
import hashlib

file = '/Users/Me/Downloads/2017-11-29-raspbian-stretch.img'

with open(file, 'rb') as f:
    contents = f.read()
    print('SHA256 of file is %s' % hashlib.sha256(contents).hexdigest())

但我收到以下错误消息:

Traceback (most recent call last):
  File "checksum.py", line 8, in <module>
    contents = f.read()
OSError: [Errno 22] Invalid argument

我做错了什么?我在 macOS High Sierra 上使用 python 3

【问题讨论】:

  • 无法复制。尝试获取任何文件或仅特定文件的校验和时会发生这种情况吗?您使用的是 Python 2 还是 Python 3?为什么您的错误消息说contents = f.read() 是第 8 行,而它只是此处给出的代码的第 6 行?
  • 你试过其他文件吗? Python 只是翻译它从操作系统 (EINVAL) 获得的错误代码,并且错误代码有可能来自文件系统驱动程序本身(因此它可能是其中的错误)。通常EINVAL 响应 read 意味着 fd 编号是错误的,但这是不寻常的情况,因为 Python 会自行控制 fd 编号的正确性。
  • @roganjosh:那里给出的答案仅适用于 Windows 系统。这个问题似乎是关于 macOS 上的问题。
  • 我现在尝试了其他文件,它们运行良好。原始 .img 文件仍然给出相同的错误消息。可能是因为它的大小为 4.92 GB?
  • @Hallvard:你使用的是什么版本的 Python?你在 32 位系统上吗?根据这两个问题的答案,可能会出现几个问题。

标签: python python-3.x macos file-io


【解决方案1】:

have beenseveralissues 在 Python 的历史上(在最近的版本中大部分已修复)一次从文件句柄读取超过 2-4 GB(32 位上也出现了无法修复的问题版本Python 的构建,它们只是缺少用于分配缓冲区的虚拟地址空间;与 I/O 无关,但最常见的是占用大文件)。可用于散列的一种解决方法是以固定大小的块更新散列(无论如何这是一个好主意,因为指望 RAM 大于文件大小是一个坏主意)。最直接的方法是将代码更改为:

with open(file, 'rb') as f:
    hasher = hashlib.sha256()  # Make empty hasher to update piecemeal
    while True:
        block = f.read(64 * (1 << 20)) # Read 64 MB at a time; big, but not memory busting
        if not block:  # Reached EOF
            break
        hasher.update(block)  # Update with new block
print('SHA256 of file is %s' % hasher.hexdigest())  # Finalize to compute digest

如果您喜欢,可以使用两个参数 iter 和一些 functools 魔术“简化”循环,将整个 while 循环替换为:

for block in iter(functools.partial(f.read, 64 * (1 << 20)), b''):
    hasher.update(block)

或者在 Python 3.8+ 上,使用 the walrus operator, := 更简单,无需导入或不可读的代码:

while block := f.read(64 * (1 << 20)):  # Assigns and tests result in conditional!
    hasher.update(block)

【讨论】:

  • 哇,太完美了。谢谢!
【解决方案2】:

哇,这可以简单得多。逐行读取文件:

with open('big-file.txt') as f:
  for i in f:
    print(i)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-07
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 2019-06-29
    • 1970-01-01
    • 2021-08-26
    相关资源
    最近更新 更多