Python Quest

Track 8 · Lesson 1 of 11

Reading text files

Open a text file, read it all at once or line by line, handle newline characters and choose the right encoding.

About 30 minBeginner4 exercisesFree

You will be able to

  • Open a text file with open() and an explicit encoding="utf-8"
  • Read a whole file with read() or a list of lines with readlines()
  • Loop over a file object line by line and remove the trailing newline
  • Explain why a file must be closed and what the file position is

So far every value your programs used was typed into the code or read with input(). Real data rarely arrives that way. A shop's price list, a week of sensor readings, a list of new customers: they live in files, and a program that can read files can work with data of any size, prepared by anyone.

A text file is a sequence of characters stored on disk, split into lines by a special newline character, written \n in Python strings. In this lesson you will open text files, read their contents in different ways and turn the lines into clean Python strings.

Every program you run here starts in its own working folder. The exercise provides the files it needs, so notes.txt in the examples below is a real file sitting next to your main.py.

Open a file, read everything, close it
f = open("notes.txt", encoding="utf-8")
text = f.read()
f.close()

print(text)
print("Characters read:", len(text))

Try it: Print repr(text) instead of text. Where do the \n characters appear?

Line by line:

  1. open("notes.txt", encoding="utf-8") finds the file in the working folder and returns a file object (often named f). Nothing has been read yet; the file object is a connection to the file.
  2. f.read() reads every character from the current position to the end and returns one string, newline characters included.
  3. f.close() releases the file. The operating system limits how many files a program may have open, and on some systems an open file cannot be renamed or deleted, so close a file as soon as you are done with it. In the next lesson you will meet the with statement, which closes files for you.

The first argument is the file name (or a path to it). If no file with that name exists, open() raises FileNotFoundError; you will handle that gracefully later in this track.

Encodings

On disk a file holds bytes, not characters. An encoding is the rule that turns bytes into characters. UTF-8 is the standard today: it can store every character, from A to é to Arabic letters, and nearly every modern file uses it.

If you leave out encoding=, Python uses your computer's default, which differs between systems. Always pass encoding="utf-8" for text files unless you know a file uses something else. Reading with the wrong encoding does not always fail; sometimes it silently produces garbled text:

The right and the wrong encoding
right = open("menu.txt", encoding="utf-8")
print(right.read())
right.close()

wrong = open("menu.txt", encoding="latin-1")
print(wrong.read())
wrong.close()

Try it: Change latin-1 to ascii and run it. ASCII has no é, so this time Python refuses with an error instead of guessing.

Reading line by line

Most data files are organised in lines: one record, reading or item per line. There are three common ways to get at them:

CodeGives you
f.read()one string with the whole file
f.readlines()a list of strings, one per line, each still ending in "\n"
for line in f:each line in turn, also ending in "\n"

Looping over the file object is the most common choice: it reads one line at a time, so it works for files of any size. Each line still carries its newline character, so you usually remove it with .strip() (removes spaces and newlines at both ends) or .rstrip("\n") (removes only the newline at the end).

Looping over lines and cleaning them
f = open("shift.txt", encoding="utf-8")
for line in f:
    print(repr(line))
f.close()

print("---")

f = open("shift.txt", encoding="utf-8")
names = []
for line in f:
    name = line.strip()
    if name:              # skip blank lines
        names.append(name)
f.close()
print(names)

Try it: Remove the if name: check. What appears in the list for the blank line?

The file position

A file object remembers how far it has read, called its position. read() moves the position to the end, so a second read() returns an empty string "". f.readline() (singular) reads one line and moves the position to the start of the next one. If you need the contents twice, keep them in a variable rather than reading again.

Predict the output

f = open("steps.txt", "w", encoding="utf-8")
f.write("open\nread\nclose\n")
f.close()

f = open("steps.txt", encoding="utf-8")
first = f.readline()
rest = f.read()
f.close()
print(repr(first))
print(repr(rest))

Guided practice · ●difficulty 1 of 5 · about 4 min

Show a welcome message from a file

A hotel kiosk shows a welcome message that the staff can edit in the file welcome.txt. Write a program that opens welcome.txt with encoding="utf-8", reads the whole file and prints its contents.

With the provided file the output is:

Welcome to Hotel Qamar.
Breakfast is served from 6:30 to 10:30.
Late checkout: ask at reception.

Your program must print whatever the file contains, not a copy of this text.

Files in your working folder: welcome.txt

welcome.txt

Welcome to Hotel Qamar.
Breakfast is served from 6:30 to 10:30.
Late checkout: ask at reception.

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Challenge · ●●difficulty 2 of 5 · about 7 min

Load a shopping list

A café keeps its weekly shopping list in a text file, one item per line. People edit it by hand, so some lines have extra spaces and there are blank lines between groups.

Write a function load_items(path) that opens the file at path (UTF-8), and returns a list of the items in file order with surrounding spaces and newlines removed. Blank lines (or lines with only spaces) are skipped.

With shopping.txt containing

milk
  coffee beans

sugar
cardamom

load_items("shopping.txt") returns ['milk', 'coffee beans', 'sugar', 'cardamom']. An empty file gives [].

Files in your working folder: shopping.txt

shopping.txt

milk
  coffee beans

sugar  
cardamom

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Debugging · ●●difficulty 2 of 5 · about 6 min

Fix the report that always counts zero lines

A warehouse script reports the size of a delivery note: how many characters and how many lines it has. describe(path) should return a tuple (characters, lines).

For delivery.txt (three lines, 49 characters including newlines) it should return (49, 3), but it returns (49, 0) for every file. Find out why and fix it so both numbers are right.

Files in your working folder: delivery.txt

delivery.txt

Pallet 1: printer paper
Pallet 2: toner
Pallet 3

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Edge cases · ●●difficulty 2 of 5 · about 5 min

Read the title line

Every report file in a clinic starts with a title line, such as Weekly appointments - Palm Grove Clinic. Write title_of(path) that returns the first line of the file without its newline character.

Some files are empty because the report was never filled in: for those, return the empty string "" instead of crashing. A file might also contain only one line with no newline at the end.

Example: for report.txt the result is 'Weekly appointments - Palm Grove Clinic'.

Files in your working folder: report.txt

report.txt

Weekly appointments - Palm Grove Clinic
Mon 12
Tue 9
Wed 14

Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.

Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type

Output

Run your code to see its output, or Check to test it against the requirements.

The solution becomes available after you pass, or after all three hints and two checks.

Summary

  • open(name, encoding="utf-8") returns a file object; close it with f.close() when you are finished.
  • read() returns the whole file as one string; readlines() returns a list of lines; looping over the file gives one line at a time.
  • Lines read from a file keep their trailing "\n"; strip() or rstrip("\n") removes it, and an empty result means a blank line.
  • The file object remembers its position, so a second read() returns "".
  • Always state the encoding; UTF-8 handles every character, and the wrong encoding can silently garble text.