Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if file is opened in binary or text mode?

Tags:

python

Given a file object, how do I determine whether it is opened in bytes mode (read returns bytes) or in text mode (read returns str)? It should work with reading and writing.

In other words:

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

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

(Another question which sounds related is not. That question is about guessing whether a file is binary or not from it's contents.)

like image 675
jdm Avatar asked Jun 16 '17 08:06

jdm


People also ask

How can you tell if a file is text or binary?

File extensions We can usually tell if a file is binary or text based on its file extension. This is because by convention the extension reflects the file format, and it is ultimately the file format that dictates whether the file data is binary or text.

What is the difference between text mode and binary mode?

When we try to read or write files in our program, usually there are two modes to use. Text mode, usually by default, and binary mode. Obviously, in text mode, the program writes data to file as text characters, and in binary mode, the program writes data to files as 0/1 bits.

Which mode is used to open a binary file?

To open a file in binary format, add 'b' to the mode parameter. Hence the "rb" mode opens the file in binary format for reading, while the "wb" mode opens the file in binary format for writing.


2 Answers

File objects have a .mode attribute:

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

This limits the test to files; in-memory file objects like TextIO and BytesIO do not have that attribute. You could also test for the appropriate abstract base classes:

import io

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

or the inverse

def is_binary(f):
    return not isinstance(f, io.TextIOBase)
like image 126
Martijn Pieters Avatar answered Sep 20 '22 04:09

Martijn Pieters


For streams opened as reading, perhaps the most reliable way to determine its mode is to actually read from it:

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

Through it does have a caveat that it won't work if the stream was already closed (which may raise IOError) it would reliably determine binary-ness of any custom file-like objects neither extending from appropriate io ABCs nor providing the mode attribute.

If only Python 3 support is required, it is also possible to determine text/binary mode of writable streams given the clear distinction between bytes and text:

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

Unless you are to frequently test if a stream is in binary mode or not (which is unnecessary since binary-ness of a stream should not change for the lifetime of the object), I suspect any performance drawbacks resulting from extensive usage of catching exceptions would be an issue (you could certainly optimize for the likelier path, though).

like image 23
minmaxavg Avatar answered Sep 23 '22 04:09

minmaxavg