The Binary Modes
There is no new table to learn. The six binary modes are the six you already know with the letter b added — and 'wb' empties a file exactly as 'w' does. What the b changes is what travels in and out.
1The same six, with a b
'rb'The file must already exist.
'wb'Creates the file — and empties it if it was there.
'ab'Adds to the end. Nothing already saved is lost.
'rb+'The file must exist. Writing overwrites from the pointer.
'wb+'Empties the file first, then allows both.
'ab+'Adds at the end, and lets you read as well.
2What the b actually changes
| Without b (text mode) | With b (binary mode) | |
|---|---|---|
| What travels in and out | str — strings | bytes |
| write() takes | a string | bytes |
| Line endings | translated for your OS | left exactly as they are |
| Used with | write(), read(), readline() | pickle.dump(), pickle.load() |
| Suits | .txt .py .csv | .dat and every other object file |
f.write() on a binary file. pickle.dump() makes the bytes and writes them, and pickle.load() reads them and rebuilds the object. Your side of it stays lists and dictionaries.3What happens if you forget the b
There is no default binary mode. Leave the b off and Python opens the file as text, and then tries to read those bytes as characters:
f = open('save.dat', 'r')
print(f.read())
f.close()Traceback (most recent call last):
File "forgot_the_b.py", line 2, in <module>
print(f.read())
^^^^^^^^
File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byteThe same mistake the other way round:
import pickle
f = open('oops.dat', 'w')
pickle.dump([1, 2], f)
f.close()Traceback (most recent call last):
File "wrong_way_round.py", line 4, in <module>
pickle.dump([1, 2], f)
TypeError: write() argument must be str, not bytesUnicodeDecodeError means you opened a binary file in text mode — Python tried to turn the bytes into letters and one of them was not a letter. TypeError: write() argument must be str, not bytes means the opposite: you gave bytes to a file opened for text. Both are one missing b.And f.write() on a binary file wants bytes, not a string, which is the third version of the same complaint:
f = open('oops.dat', 'wb')
f.write('hello')Traceback (most recent call last):
File "strings_are_not_bytes.py", line 2, in <module>
f.write('hello')
TypeError: a bytes-like object is required, not 'str'4What a binary file actually holds
Read one with 'rb' and you can see the bytes. This is the file made by pickling {'player': 'Ravi', 'level': 3, 'points': 120}:
f = open('save.dat', 'rb')
data = f.read()
f.close()
print(data)
print(len(data), 'bytes')b'\x80\x04\x95*\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x06player\x94\x8c\x04Ravi\x94\x8c\x05level\x94K\x03\x8c\x06points\x94Kxu.' 53 bytes
b in front of the quotes says these are bytes, not a string. You can pick out player and Ravi in the middle — pickle does not hide your text — but the numbers and the structure are stored in a form only pickle understands. You never read a file this way in practice; pickle.load() does it for you.5Closing a binary file
Exactly as before. f.close() empties the buffer onto the disk and releases the file, and everything the closing lesson said still holds — including that a program which writes and never closes can leave a file with nothing in it.
import pickle
f = open('marks.dat', 'wb')
pickle.dump([78, 91, 65], f)
f.close()And with works the same way too, closing the file at the end of the block:
import pickle
with open('marks.dat', 'wb') as f:
pickle.dump([78, 91, 65], f)
print('closed?', f.closed)closed? True
6Which mode for which job
'wb'The first program of the chapter. Careful — it wipes an existing file.
'rb'Nothing can be damaged in this mode, which is why it is the one to use unless you mean to write.
'ab'The mode real programs use most. A second run adds; it does not replace.
'rb+'Read and write through one handle. The update lesson shows why this one needs care.
7Recap
The text modes with a b. The letter still decides everything: r keeps, w erases, a adds.
No characters, no encoding, no line-ending translation.
Leave the b off and the file is opened as text, whatever its name ends with.
A binary file opened in text mode. Python tried to read bytes as letters.
The two halves do not match: bytes into a text file, or a string into a binary one.
Same method, same reasons — and with works exactly as it does for text.
- 1
Pickle a list into
test.dat, then open the file in'r'and read it.Hint · UnicodeDecodeError. The b is not optional.
- 2
Open
test.datin'rb'and printf.read().Hint · Bytes, starting with b'. Your text is visible inside them.
- 3
Write two programs that pickle one list each into the same file — one using
'wb', one using'ab'.Hint · Run each twice and see which file grows.
- 4
Rewrite one of your programs with
with open(...)and checkf.closedafterwards.Hint · True. Binary files are closed by the block just like text ones.
Which mode creates a binary file, erasing it if it already exists?
What does the b in 'rb' change?
pickle.dump([1, 2], f) where f was opened in 'w'. What happens?
Which mode would you use to add more records to an existing binary file?