Python 文件对象是真实文件吗?

Is a Python File object a real file?

在Python中,一个文件对象可能指向一个真实的文件、stdin、stdout、stderr,甚至是其他东西。因此它可以是 类文件,或 真实文件,如 file.flush.

所述

如何知道一个文件是不是真实文件?我找到了一些猜测的方法,但 none 似乎真的很可靠:

  1. file not in [sys.stdin, sys.stdout, sys.stderr] -- 看起来最安全,但仅适用于那些标准类型,不是非常通用的解决方案。
  2. os.path.isfile(file.name) -- 看起来很安全,但我猜如果在某些创建模式下打开新文件可能无法工作。
  3. file.fileno() == 0 -- 这假定方法未实现,默认实现 returns 0,正常实现永远不会 return 0.
  4. file.name.startswith('<') -- 这实际上假设文件系统不允许在文件名中使用 <

为什么我需要知道这个,因为我想提前关闭它,使用 with file as f: 可能会关闭 stdin/stdout,这听起来是个坏主意。

一般来说,您应该只对称地使用 with ... as f:,也就是说,使用您 open 或在 with 语句中获得的文件句柄。


在 UNIX 上,您可以检查 .fileno() - 0 代表标准输入,1 代表标准输出,2 代表标准错误;通常你不应该关闭这些流,因为真的没有办法再重新打开它们了。


file.name 并不是真正的 100% 证明方法,因为许多流可以有一个名称,即使它们不是真实的文件,并且该特殊名称可能与磁盘上的现有文件冲突:

>>> import os.path
>>> os.path.exists(sys.stdin.name)
True
>>> sys.stdin.name
'<stdin>'

(提示,就在我做之前 touch '<stdin>'

此外,在 UNIX 中,通常在打开临时文件后立即取消链接,因此它们不再存在;另一方面,即使是现有文件在打开后也可能被 重命名,因此原始名称并不存在。


如果你想知道一个标准流是否被重定向到一个文件,你可以这样做:

>>> import os
>>> import stat   
>>> stat.S_ISREG(os.fstat(sys.stdout.fileno()).st_mode)
False

S_ISREG returns True 如果模式描述的是普通文件(此处输出到终端,因此为 False);同样,您可以使用 isatty:

查看是否有任何文件被重定向到 terminal
>>> os.isatty(sys.stdout.fileno())
True
来自 Python 的套接字库的

This part 可能会有帮助(其中 file 是一个文件对象):

    try:
        fileno = file.fileno()
    except (AttributeError, io.UnsupportedOperation) as err:
        raise _GiveupOnSendfile(err)  # not a regular file
    try:
        fsize = os.fstat(fileno).st_size
    except OSError as err:
        raise _GiveupOnSendfile(err)  # not a regular file