Why a Binary File
You can already write anything into a text file. So why is there another kind? Because of one sentence that sounds harmless and is not: a text file gives back text. Whatever you put in, what comes out is characters.
1Saving a list in a text file
Here is a list of marks. write() only takes strings, so the usual move is str(). It works — the file looks perfect if you open it in Notepad:
[78, 91, 65]Now read it back and try to use it:
marks = [78, 91, 65]
f = open('marks.txt', 'w')
f.write(str(marks))
f.close()
f = open('marks.txt', 'r')
back = f.read()
f.close()
print(back)
print(type(back))
print(back[0])
print(back + [50])[78, 91, 65]
<class 'str'>
[
Traceback (most recent call last):
File "losing_the_list.py", line 14, in <module>
print(back + [50])
~~~~~^~~~~~
TypeError: can only concatenate str (not "list") to strprint(back)It LOOKS like the list. That is what makes this so confusing — printing gives you exactly what you saved.
print(type(back))But it is a str. The square brackets are two characters in a piece of text, not a list.
print(back[0])'[' — the first CHARACTER. On the real list, marks[0] would be 78.
print(back + [50])TypeError. You cannot add a list to a string, and there the illusion ends.
int() over every piece — and write that code again for every different kind of value you ever save.2And it gets worse than a list
A list of numbers can just about be rebuilt by hand. Now think about what a real program holds:
{'roll': 1, 'name': 'Ravi', 'marks': 78}Rebuilding this from text means splitting on commas AND on colons, and remembering which parts were numbers.
[[1, 'Ravi', 78], [2, 'Meera', 91]]Now the commas inside a record and the commas between records look exactly the same.
['Kumar, Ravi', 78]Split on the comma and the record quietly breaks into three pieces. The data itself has defeated your rule.
[78.5, 91.0, 65]int() or float()? You now have to look at every piece to decide what it used to be.
3The answer: store the object, not a picture of it
A binary file does not hold characters. It holds bytes — and Python can turn a whole object into bytes and turn those bytes back into the same object. Same program as before, two lines changed:
import pickle
marks = [78, 91, 65]
f = open('marks.dat', 'wb')
pickle.dump(marks, f)
f.close()
f = open('marks.dat', 'rb')
back = pickle.load(f)
f.close()
print(back)
print(type(back))
print(back[0])
print(back + [50])[78, 91, 65] <class 'list'> 78 [78, 91, 65, 50]
type() says list. back[0] is 78, not a bracket. And you can add another mark to it, because it is a list — not a drawing of one. Nothing had to be split, stripped or converted.Those three new things — import pickle, 'wb' and dump()/load() — are the whole chapter, and each gets a lesson of its own. This page only had to convince you they are worth learning.
4Text file and binary file, side by side
| Text file | Binary file | |
|---|---|---|
| Holds | characters | bytes |
| You write | strings, with write() | objects, with pickle.dump() |
| You get back | a string, always | the same object you saved |
| Open it in Notepad | readable | nonsense on the screen |
| Modes | 'r', 'w', 'a' | 'rb', 'wb', 'ab' |
| Good for | notes, reports, anything a person reads | records a program will read back |
5Try it
Both round trips in one program. Change marks to a dictionary and run it again — the text version gets worse and the pickle version does not change at all:
6Recap
Whatever you saved, read() hands you a string. The type is gone.
'[78, 91, 65]' prints the same as the list and behaves nothing like it.
Dictionaries, lists of lists, commas inside the data — every one of them breaks a simple splitting rule.
Not characters. Open one in Notepad and you get nonsense, because it was never meant for a person.
dump() to save, load() to get it back — as the same type it was.
The b is what makes the file binary. Same modes as text files, one letter longer.
- 1
Save a dictionary in a text file with
str(), read it back, and tryback['name'].Hint · TypeError: string indices must be integers.
- 2
Do the same with pickle and try it again.
Hint · It works, because what came back is a dictionary.
- 3
Open a
.datfile you made with pickle in Notepad.Hint · Close it without saving. Notepad would rewrite the bytes.
- 4
Write the list
['Kumar, Ravi', 78]into a text file and try to split it back into two pieces.Hint · The comma inside the name is the problem, and it has no easy fix.
A list is saved in a text file with f.write(str(marks)). What does read() give back?
back = '[78, 91, 65]'. What is back[0]?
What does a binary file hold?
When is a text file the better choice?