【问题标题】:Why do I get IOError when I use msvcrt in Python 2.x?为什么在 Python 2.x 中使用 msvcrt 时会出现 IOError?
【发布时间】:2017-03-30 21:14:06
【问题描述】:

我正在尝试使用Python 2.x 中的 HTML-PDF Web 服务在 Windows 中生成 PDF。这个链接Python 2.x - Write binary output to stdout? 说如果我将二进制文件写入标准输出,我需要修改它。

def generate_pdf():
    pdf = callservice(html)
    if pdf is not None and sys.platform == "win32":
        import os, msvcrt
        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    return pdf

def process():
    pdf = generate_pdf()
    # This comes as IOError Errno 12 not enough space

E:\ 运行此程序的驱动器有 10 GB 可用空间。有谁知道会发生什么? C:\ 驱动器也有 10 GB 可用空间。我们是否应该检查msvcrt 的源代码以查看发生了什么。我正在尝试检查。

【问题讨论】:

  • 您是否正在将 PDF 写入标准输出,该标准已被重定向到驱动器 E: 或驱动器 C: 上的文件?
  • sys.stdout.fileno() 只是 1,我从 Shell 将这个脚本作为 python file.py 运行,这能回答你的问题吗?
  • 如果您没有将标准输出重定向到磁盘文件,我认为没有理由将其更改为二进制模式。
  • 您的脚本在哪里尝试创建文件?在工作目录中?工作目录取决于 python.exe 的启动方式。它与“file.py”的位置无关。
  • Windows C 运行时实现低 (POSIX) 和标准 I/O。 Python 2.x file 对象包装 C 标准 I/O FILE 流,这些流包装 POSIX 整数文件描述符(依次映射到实际的 Windows File 句柄)。 fileno 方法返回文件描述符。最初,C 运行时的 3 个标准 FILE 流——stdinstdoutstderr——作为文件描述符 0、1 和 2 打开,最初是 Python 的 sys.stdinsys.stdoutsys.stderr 包装对应的 C FILE 流。

标签: python windows python-2.7


【解决方案1】:

这个answer 原则上解释了发生了什么,并且回溯会显示一个确切的失败调用。

特别是,当没有足够的数据可以读取时,尝试sys.stdin.read() 大于 32767 字节的数据块将导致IOError“[Errno 12] 没有足够的空间”。考虑在 Windows 7 上运行以下示例:

python -c "import sys; data = sys.stdin.read(32768)"

【讨论】:

  • 这是人们解释错误信息时的问题。 OP 说这是一个IOError“无磁盘空间”。但是 Windows CRT 没有这样的消息。有ENOMEM(12,“空间不足”)和ENOSPC(28,“设备上没有剩余空间”)。
  • 你给出了一个ENOMEM 的例子。显然您使用的是 Windows 7 或更早版本,它使用旧的 ALPC 控制台子系统。这会在 conhost.exe 和客户端进程 python.exe 之间建立一个 64K 的共享堆。尝试分配大于共享堆中最大可用块的读取缓冲区时,您会遇到与内存相关的错误。 Windows 8+ 有一个完全不同的控制台子系统,它使用驱动程序而不是 ALPC,并且没有这个问题。
  • 感谢您的更正,您在所有细节上都是正确的。我的例子与问题没有太大关系。
  • 您太仓促了,无法假设该示例不相关。 Nishant 的代码出现ENOMEM 错误——可能是在控制台时以二进制模式写入stdout。在 Windows 8 之前,这仅限于 64K 堆中与 conhost.exe 共享的最大空闲块。到目前为止,在 cmets 中,我还没有看到将 stdout 设置为二进制模式的理由——如果 stdout 被重定向到磁盘文件或管道,而不是控制台,那会很好。
  • @Nishant,您实际上是在将 pdf 文件写到 stdout 吗?如果是这样,重定向到一个文件,例如python script.py > output.pdf。 shell 将打开output.pdf 并将句柄作为StandardOutput 句柄传递给python.exe。在启动时,Python 中的 C 运行时会将其映射到文本模式下的低 I/O 文件描述符 1,该文件描述符由 C stdout 流包装,该流由 Python sys.stdout 包装。然后,您的脚本必须将文件描述符 1(即 sys.stdout.fileno())更改为二进制模式,正如您已经在做的那样,写入“output.pdf”,而 C 运行时无需将 "\n" 转换为 "\r\n"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 2015-05-25
  • 2022-07-02
  • 2014-09-23
  • 2011-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多