Chapters
Python114 chapters

Files and errorsChapter 80 of 114

Read Files

Read a whole file, a line at a time, or lazily for a big one.

Setting up

Every example below reads this file:

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada,1815\nGrace,1906\nKatherine,1918\n")

print("written")

Output

written

read gives you the whole thing

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada,1815\nGrace,1906\n")

with open("people.txt", encoding="utf-8") as f:
    content = f.read()

print(repr(content))
print(len(content))

Output

'Ada,1815\nGrace,1906\n'
20

One string, newlines included. Fine for a configuration file, bad for a five-gigabyte log.

readlines gives you a list

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada,1815\nGrace,1906\n")

with open("people.txt", encoding="utf-8") as f:
    lines = f.readlines()

print(lines)

Output

['Ada,1815\n', 'Grace,1906\n']

The newline stays on the end of each line. That trips people up, and strip() is the usual answer.

Looping is the right default

A file object is iterable, and gives one line at a time without loading the rest:

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada,1815\nGrace,1906\nKatherine,1918\n")

with open("people.txt", encoding="utf-8") as f:
    for line in f:
        name, year = line.strip().split(",")
        print(f"{name} was born in {year}")

Output

Ada was born in 1815
Grace was born in 1906
Katherine was born in 1918

This works on a file far larger than memory, because only one line is held at a time. Make it your default.

Add enumerate when you want line numbers:

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada\nGrace\n")

with open("people.txt", encoding="utf-8") as f:
    for number, line in enumerate(f, start=1):
        print(number, line.strip())

Output

1 Ada
2 Grace

Stripping the newline

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada\nGrace\n")

with open("people.txt", encoding="utf-8") as f:
    names = [line.strip() for line in f]

print(names)

Output

['Ada', 'Grace']

splitlines() does the same job on a string you already have, and drops the newlines for you:

Python
text = "Ada\nGrace\n"
print(text.splitlines())
print(text.split("\n"))

Output

['Ada', 'Grace']
['Ada', 'Grace', '']

Note the trailing empty string from split("\n"). splitlines() is almost always what you want.

Reading a bit at a time

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada,1815\n")

with open("people.txt", encoding="utf-8") as f:
    print(repr(f.read(3)))
    print(repr(f.readline()))

Output

'Ada'
',1815\n'

The file remembers its position, so the second call carries on where the first stopped.

Reading is one-way

Once you have read to the end, there is nothing left:

Python
with open("people.txt", "w", encoding="utf-8") as f:
    f.write("Ada\n")

with open("people.txt", encoding="utf-8") as f:
    print(repr(f.read()))
    print(repr(f.read()))
    f.seek(0)
    print(repr(f.read()))

Output

'Ada\n'
''
'Ada\n'

seek(0) rewinds. If you find yourself doing that a lot, read into a list once instead.

CSV files

Do not split on commas by hand. A real CSV can have commas inside quoted fields, and csv handles it:

Python
import csv

with open("people.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["name", "note"])
    writer.writerow(["Ada", "maths, and computing"])

with open("people.csv", encoding="utf-8", newline="") as f:
    for row in csv.reader(f):
        print(row)

Output

['name', 'note']
['Ada', 'maths, and computing']

Splitting that second row on commas would have given three fields instead of two.

Test yourself

2 questions

What is the best default way to read a large file?

Show the answer

Loop over the file object, one line at a time — Only one line is held at a time, so it works on files larger than memory.

What does readlines() leave on the end of each line?

Show the answer

The newline character — strip() is the usual answer, or splitlines() when you already have the text.

Next chapter

Write Files

Create, overwrite and append, without losing what was there.