File I/O
Contents
File I/O#
I/O is a shorthand way of referring to input and output. The input()
and
print()
functions are two examples of input and output. In this lesson
we’ll learn another: how to read from and write to files.
Table of Contents
Part 1: Reading Files#
Sometimes in our programs we need to access information that is stored in a file. In programming this is called reading a file and that’s what we’ll learn first.
Part 1.1: Reading whole files#
In this section we will get the contents of a file containing a grocery list then then print it to the screen.
A. Create groceries.txt
#
First we’ll need a file to read from. Paste the following lines into a new file
groceries.txt
, located in the same directory you will be running the
script from, or the working directory.
1- eggs
2- milk
3- flour
B. Create groceries.py
#
1. Create a second file groceries.py
also in the working directory.
2. To interact with files we start by using Pythons built-in open()
function.
It returns a file handler object, which we’ll assign to a variable
fh
. The open()
function takes at least one argument, the location of the
file to open. In this case we want a string with the filename:
"groceries.txt"
.
3. The file handler object represents the connection to the file and
provides methods for interacting with the file. In this case, we are
interested in the .read()
method which returns the entire contents of the
file as a string. We’ll assign the string to the variable contents
.
4. We’re done with the file now so we’ll call the .close()
method on fh
to
free up the computer resources used to manage the file. It is important to
always close a file handler when its no longer needed to avoid bugs that may
slow down your computer or interfere with the file you opened.
5. Finally, we’ll print the title "Groceries"
underlined with =
followed by the
contents of the file.
1# open the file and create a file handler object
2fh = open("groceries.txt")
3
4# get a string with the contents of the file
5contents = fh.read()
6
7# close the file handler
8fh.close()
9
10# print a header followed by the file contents
11print("Groceries")
12print("=========")
13print(contents)
6. When you run your script you should see a nicely formatted grocery list, all ready for a shopping trip.
Groceries
=========
- eggs
- milk
- flour
Part 1.2: Exercise#
(reading files)
In this exercise you’ll be reading a file and printing its contents to the screen, just like you did above but with a different file.
Copy the following text and paste it into a file named
mug-brownie.md
in your working directory.mud-brownie.md
Mug Brownie =========== Ingredients ----------- - 1/4 cup flour (30 g) - 1/4 cup sugar (50 g) - 2 tablespoons (13 g) cocoa (natural, unsweetened) - Pinch of salt - Tiny pinch of cinnamon - 1/4 cup water (60 ml) - 2 tablespoons (30 ml) melted butter, or neutral oil - 1/8 teaspoon vanilla extract - 1 small scoop of ice cream or 1 or 2 teaspoons heavy whipping cream to serve Instructions ------------ 1. **Add the dry ingredients to the mug and stir** Place flour, sugar, cocoa, salt, and cinnamon in a microwave safe ceramic mug. Stir with a fork or spoon to mix well and break up any clumps. 2. **Add the wet ingredients and stir** Add the butter or oil, water, and vanilla to the cup and stir until the mixture is smooth and there are no lumps. 3. **Zap in microwave** Place in microwave and heat on high until the mixture is cooked through, about a 1 minute and 40 seconds for a 1000 watt microwave, or 1 minute 10 seconds on a 1650 watt microwave. You may have to experiment and adjust the time for less or more powerful microwaves. If you don't know the power level on your microwave, start with 60 seconds and increase until the brownie is done. It should still be moist when cooked through, not dry.
Create a new file
recipe.py
for this exercise.Use the
open()
function to get a file handler for themug-brownie.md
file.Use the
.read()
method to get the contents of the file and assign it to a variablerecipe
.Use the
.close()
method to close the file handler.Print the
recipe
.
Solution to Exercise 62 (reading files)
1fh = open("mug-brownie.md")
2recipe = fh.read()
3fh.close()
4
5print(recipe)
Part 1.3: Reading lines#
Sometimes instead of getting the entire contents of a file at once, we want to go through each line line for more fine grained control.
This is where the .readlines()
method on file handler objects comes in. It
returns a list, where each element is one line from the file.
A. Modify recipes.py
#
In this section we’ll modify the recipes.py
file to use the .readlines()
method in a for
loop.
1. Since we’ll be printing each line as it is read, first we’ll need to move the header lines to the beginning of the script so that they are printed first.
2. As before, we’ll need a file handler object from open()
, so we can leave that
line unchanged.
3. This time we’ll replace the .read()
line with a for
loop, iterating over the
list returned by fh.readlines()
. We’ll call the item variable line
, since
it will contain a line from the file in each iteration.
4. Now the list returned by .readlines()
retains the carriage return ("\n"
) at
the end of each line
string. So when we print each line
in the for loop,
we’ll tell the print()
function not to add a newline by passing it the end
keyword argument with a value of ""
.
5. Finally, we’ll still want to .close()
the file handler, so that line can stay
the way it is.
1# print a header
2print("Groceries")
3print("=========")
4
5# open the file and create a file handler object
6fh = open("groceries.txt")
7
8# loop through each line of the file
9for line in fh.readlines():
10
11 # print the line which includes the trailing "\n"
12 # and pass print an empty string for end
13 # so it doesn't add an extra newline
14 print(line, end="")
15
16# close the file handler
17fh.close()
6. When you run your script the output should be the same.
Groceries
=========
- eggs
- milk
- flour
Part 1.4: Exercise#
(reading lines)
In this exercise you’ll be reading each line of a todo.txt
file using
the .readlines()
method then printing each line with a *
at the beginning.
Copy the following text and paste it into a file named
todo.txt
in your working directory that contains a list of items to do.todo.txt
dishes laundry homework
Create a new file
todo.py
for this exercise.Use the
open()
function to get a file handler for thetodo.txt
file.Use a
for
loop to iterate over the list returned byfh.readlines()
and name the item variableline
.In the for loop, print
"* "
followed by eachline
and tellprint()
not to add an extra newline by passing theend
keyword argument with an empty string.Use the
.close()
method to close the file handler.
Your output should look like this:
* dishes
* laundry
* homework
Solution to Exercise 63 (reading lines)
1fh = open("todo.txt")
2for line in fh.readlines():
3 print("*", line, end="")
4fh.close()
Part 2: Writing Files#
Sometimes we need to create or modify files. That’s what we’ll be learning in this section.
Part 2.1: Creating or truncating#
The open()
function takes an optional mode
argument, which is a string that
indicates what we plan to do with the file. The default is "r"
for read mode.
To write to a file though, we’ll open it in write mode by passing the optional
mode argument "w"
to open()
. Write mode will either create or overwrite the
file and open it with permission to write.
A. Write to packing.txt
#
In this section we’re going write the contents of a to_pack
list to a
packing.txt
file.
1. Create a file packing.py
, add a create_packing()
function and
call it. The rest of your code in this section will go in this function.
2. Add a to_pack
list of strings, things to pack.
3. Get a file handler fh
by calling open()
with the arguments "packing.txt"
and "w"
for write mode. Be aware: the file is created or
truncated as soon as open()
is called when in write mode.
4. Using a for
loop iterate over the to_pack
list and name the item variable
thing
.
5. In write mode, file handler objects keep a buffer where the text to be
written to the file is stored until .close()
is called. Inside the loop we’ll
add each thing
to the buffer by calling the .write()
method on fh
with
the argument "- thing\n"
. Don’t forget to add a "\n"
to the end
of each string or the file will all be smooshed onto one long line!
6. As always, we need to .close()
the file handler when we’re done with the
file. It is especially important in write mode because that is when the buffer
is written to disk.
1def create_packing():
2 """Create or overwrite packing.txt and write contents of to_pack list on each
3 line"""
4
5 # create a list of things to pack
6 to_pack = [
7 "phone charger",
8 "passport",
9 "weapons",
10 "cash",
11 ]
12
13 # open packing.txt in write mode, which is
14 # when the file is created or truncated
15 fh = open("packing.txt", "w")
16
17 # iterate through the to_pack list
18 for thing in to_pack:
19 # add each thing to the file buffer
20 # with a "\n" suffix so its on its own line
21 fh.write(f"- {thing}\n")
22
23 # close the file handler, which is when the the file is written to disk
24 fh.close()
25
26if __name__ == "__main__":
27 create_packing()
7. Now open up your packing.txt
file. It should look something like this:
- phone charger
- passport
- weapons
- cash
Part 2.2: Exercise#
(writing files)
In this exercise you’ll make a people
list and write it to a
xmas_shopping.txt
file.
Create a file
xmas_shopping.py
for this script, add acreate_xmas_shopping()
function and call it. Put the rest of the code from this exercise in that function.Add a
people
list of strings, names of people to shop for.Open the file
xmas_shopping.txt
in write mode and name the file handler objectfh
.Iterate through your list of
people
using afor
loop and name your items variablename
.In the loop
.write()
a line to the buffer:"[ ] name\n"
..close()
the file handler
xmas_shopping.txt
should look something like this:
[ ] Buffy
[ ] Xander
[ ] Willow
[ ] Giles
Solution to Exercise 64 (writing files)
1def create_xmas_shopping():
2 """Create or overwrite xmas_shopping.txt and write contents of people list on each
3 line"""
4
5 people = [
6 "Buffy",
7 "Xander",
8 "Willow",
9 "Giles",
10 ]
11
12 fh = open("xmas_shopping.txt", "w")
13 for name in people:
14 fh.write(f"[ ] {name}\n")
15
16 fh.close()
17
18if __name__ == "__main__":
19 create_xmas_shopping()
Part 2.3: Adding to files#
Often instead of writing a whole file from scratch we just want to add to the end of it. That’s when we want append mode.
A. Add to packing.txt
#
In this section we’re going append a single line to the packing.txt
file.
1. Open the packing.py
file, add a addto_packing()
function and call it. The
rest of your code in this section will go in this function.
2. Get a file handler fh
by calling open()
with the arguments "packing.txt"
and "a"
for append mode.
3. Add a single line the buffer by calling the .write()
method on fh
with the
argument "- thing to pack\n"
.
4. Finally, .close()
the file handler.
26def addto_packing():
27 """Append a single line to the packing.txt file"""
28
29 # open the file in append mode
30 fh = open("packing.txt", "a")
31
32 # add a single line to the file buffer
33 fh.write("- first aid kit\n")
34
35 # close the file handler, which is when the the file is written to disk
36 fh.close()
37
38if __name__ == "__main__":
39 create_packing()
40 addto_packing()
5. After running your code the packing.txt
file should look something like this:
- phone charger
- passport
- weapons
- cash
- first aid kit
Part 2.4: Exercise#
(appending to files)
In this exercise you’ll append a single line to the xmas_shopping.txt
file.
Open the file
xmas_shopping.py
, add aaddto_xmas_shopping()
function and call it. Put the rest of the code from this exercise in that function.Open the file
xmas_shopping.txt
in append mode and name the file handler objectfh
..write()
a line to the buffer:"[ ] name\n"
..close()
the file handler
You should see the new name in xmas_shopping.txt
, something like:
[ ] Buffy
[ ] Xander
[ ] Willow
[ ] Giles
[ ] Angel
Solution to Exercise 65 (appending to files)
17def addto_xmas_shopping():
18 """Append a single line to the xmas_shopping.txt file"""
19
20 # open the file in append mode
21 fh = open("xmas_shopping.txt", "a")
22
23 # add a single line to the file buffer
24 fh.write("[ ] Angel\n")
25
26 # close the file handler, which is when the the file is written to disk
27 fh.close()
28
29if __name__ == "__main__":
30 create_xmas_shopping()
31 addto_xmas_shopping()
Part 4: Automatic file closing#
There are lots of reasons that it is important to always .close()
a file
handler object when you’re done with it.
In theory Python is supposed to close any open file handlers when a program ends, but it’s not a guarantee.
The more files are open, the more resources are used, and the more space is taken up in memory. Leaving things open unnecessarily could slow down your program and your computer while your program runs.
File changes usually don’t go into effect until you close the file handler. If another part of your program is counting on those changes, you’ll run into unpleasant surprises if you haven’t yet closed it.
There are limits to how many files a computer can have open at a time. While it is rare to bump up against those limits in normal operation, it’s certainly the kind of trouble a programmer can get themselves into by mistake. (Imagine opening files in an infinite loop!)
Some operating systems treat open files as locked, which may prevent you from reading the file with another program or even deleting it.
But sometimes mistakes happen. It’s easy to forget, and what if there is an error after opening the file but before it is closed?
That’s where the with
statement and context managers
come in.
Part 4.1: the with
statement#
File handlers in Python have the feature of being context managers,
which are objects designed to know how to do their own housekeeping for use in
a with
statement.
More on that later, but first lets take a quick look at the syntax of a with
statement:
with EXPN as VAR:
BODY
For files it looks like:
with open(...) as fh:
# do stuff with fh
|
an expression that produces a context manager |
|
variable name for the object |
|
statements that use |
So, what does that do?
The with
statement wraps a block of code with calls to internal setup and
teardown methods provided by the context manager. In particular, anything that
ends the execution of the block triggers a call to the teardown method; whether
it ended because it finished or because there was an error. Neither errors nor
^C stays the with
statement from completing the appointed teardown.
File handlers know how to clean up after themselves. That means that when used
in a with
statement .close()
is called automatically at the end of the
statement, even if there is an error in the BODY
.
Lets take a look at our very first groceries.txt
code alongside the same code
written using a with
statement.
1# open the file
2fh = open("groceries.txt")
3
4# read the contents
5contents = fh.read()
6
7# close the file handler
8fh.close()
9
10# print the file contents
11print("Groceries")
12print("=========")
13print(contents)
1# open the file
2with open("groceries.txt") as fp:
3
4 # read the contents
5 contents = fp.read()
6
7# `fh` is automatically closed
8# no need to call fh.close()
9
10# print the file contents
11print("Groceries")
12print("=========")
13print(contents)
14
Part 4.2: scores.txt
#
In this section we are going to use a with
statement to append a line with
random number to a scores.txt
file.
1. Create a new file scores.py
.
2. Import the random
module.
3. Add a add_scores()
function and call it. The rest of your code in this
section will go in this function.
4. Call random.randint()
to get a random number between 0
and 100
and assign
it to the variable score
.
5. Use a with
statement to open the "scores.txt"
:
the
EXPN
should be a call toopen()
with the arguments"scores.txt"
and"a"
for append modegive the
VAR
the namefh
in the
BODY
add a single line"score\n"
the buffer by calling the.write()
method onfh
1import random
2
3def add_scores():
4 """Append a random score between 1 and 100 to scores.py"""
5
6 # get a random number between 1 and 100
7 score = random.randint(0, 100)
8
9 # open scores.txt in append mode
10 with open("scores.txt", "a") as fh:
11
12 # add the score to the file buffer
13 fh.write(f"{score}\n")
14
15if __name__ == "__main__":
16 add_scores()
6. After you run your script scores.txt
should contain a single number, something like this:
85
7. Run your script a few more times. scores.txt
should have some new lines, something like this:
85
91
29
20
39
Part 4.3: Exercise#
(with statements)
In this exercise you’ll be reading each line of the scores.txt
file using
the .readlines()
method then printing the last line.
Open the
scores.py
file, add a new functionlast_score()
, and call it.Use a
with
statement to open the"scores.txt"
:the
EXPN
should be a call toopen()
with the argument"scores.txt"
to open the file in read mode.give the
VAR
the namefh
in the
BODY
:Use a
for
loop to iterate over the list returned byfh.readlines()
and call the item variablescore
You only need to for loop to assign the
score
variable, so in the body of the loop justcontinue
.
After the
with
statement,score
will still be assigned to the last line of the file. PrintYour last score was: score
and use theend
keyword argument to avoid adding an extra newline.
Your output should look something like this:
Your last score was: 18
Solution to Exercise 66 (with statements)
15def last_score():
16 """Print the most recent score from the scores.text file"""
17
18 # open scores.txt in read mode
19 with open("scores.txt") as fh:
20
21 # iterate through each line in the file
22 for score in fh.readlines():
23
24 # nothing to do in the loop since
25 # we just need to assign the score variable
26 continue
27
28 # print the final value of score (the last line of the file)
29 print(f"Your last score was: {score}", end="")
30
31if __name__ == "__main__":
32 add_scores()
33 last_score()
Reference#
File Modes#
These are the mode characters that can be used in the open()
function.
Type |
Char |
Name |
Description |
---|---|---|---|
writeability |
|
read |
read only (default) |
writeability |
|
write |
create a new file or overwrite existing |
writeability |
|
append |
add to the end of a file |
writeability |
|
exclusive create |
create a new file or fail if existing |
writeability |
|
read+write |
allow reading and writing |
format |
|
text |
text files (default) |
format |
|
binary |
for images and other non-text files |
They can be combined, for example:
Mode |
Description |
---|---|
|
start at the end of the file and allow both reading and writing |
|
create a new file or overwrite existing and allow reading and writing |
|
open a file in binary mode for reading only |
See Also#
Glossary#
File Io#
- file-like object#
- file object#
- file handler#
- IO object#
An object used to connect to and interact with a file.
- buffer#
A sort of temporary holding pen for data that is going from one place to another. For example, the default behavior of writable file handler objects is to append the data passed to the
.write()
function to the write buffer, then write the buffer to disk when the handler is closed. This improves preformance by reducing the number of hard disk writes.- context manager#
- context manager objects#
Python objects that know how to do their own houskeeping. More precicely, objects that provide the dunder methods
.__enter__()
and.__exit__()
intended to be used by thewith
statement for setup and teardown tasks.- truncate#
To shorten something but cutting off a part. When a text file is opened in write mode, it is truncated to zero bytes, thereby removing all content from the file.