如何确定文件是以二进制还是文本模式打开的?

16

如果给出一个文件对象,如何确定它是以字节模式打开的(read返回bytes),还是文本模式打开的(read返回str)?应该适用于读写两种情况。

换句话说:

>>> with open('filename', 'rb') as f:
...     is_binary(f)
...
True

>>> with open('filename', 'r') as f:
...     is_binary(f)
...
False

这个问题听起来与此相关,但实际上不是。那个问题是关于猜测文件是否为二进制的,而不是从其内容中确定。)

3个回答

32

文件对象具有一个 .mode 属性

def is_binary(f):
    return 'b' in f.mode

这将限制测试文件;像TextIOBytesIO这样的内存中的文件对象没有该属性。你还可以测试适当的抽象基类

import io

def is_binary(f):
    return isinstance(f, (io.RawIOBase, io.BufferedIOBase))

或者相反

def is_binary(f):
    return not isinstance(f, io.TextIOBase)

非常好,还感谢您提供文档链接并指向io模块。我只在词汇表中找到了file object的定义,这非常肤浅......另外,现在我想起来,另一种Pythonic的方法可能只是尝试读取,并在失败时捕获异常。 - jdm
由于文件可能是一个没有 .mode 属性的类似文件的对象,更安全的测试方法是:if 'b' not in getattr(file, 'mode', 'b') - Julien Palard

1

对于以读取方式打开的流,也许最可靠的确定它的模式的方法是实际从中读取:

def is_binary(f):
    return isinstance(f.read(0), bytes)

虽然有一个警告,即如果流已经关闭(可能会引发IOError),它将可靠地确定任何自定义文件对象的二进制性,无论是扩展适当的io ABC还是提供mode属性。

如果仅需要Python 3支持,则还可以确定可写流的文本/二进制模式,因为字节和文本之间有明显区别:

def is_binary(f):
    read = getattr(f, 'read', None)
    if read is not None:
        try:
            data = read(0)
        except (TypeError, ValueError):
            pass # ValueError is also a superclass of io.UnsupportedOperation
        else:
            return isinstance(data, bytes)
    try:
        # alternatively, replace with empty text literal
        # and swap the following True and False.
        f.write(b'')
    except TypeError:
        return False
    return True

除非您经常测试流是否为二进制模式(这是不必要的,因为流的二进制性在对象的生命周期内不应更改),否则我怀疑由于捕获异常的广泛使用而导致的任何性能缺陷都将是一个问题(尽管您可以针对可能更常见的路径进行优化)。


-4

有一个名为mimetypes的库,其中guess_type返回值是一个元组(type, encoding),其中type为None表示无法猜测类型(缺少或未知后缀),或者是形式为'type/subtype'的字符串。

import mimetypes
file= mimetypes.guess_type(file)

2
这不是关于文件内容的问题,而是关于文件如何打开的问题。请仔细阅读问题,他们特别提到另一个问题可能会有这个答案,但这个问题不是那个问题 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接