Reading from and Writing to Files#
Learning Objectives
Questions:
How can you read a file: all at once, line by line, or into a list?
How can you write data to a file: overwrite, append, or write multiple lines?
Objectives:
Open, read, and write text files in Python.
Understand why
with open()
is often preferable compared toopen()
/close()
.Use the correct file mode (
"r"
,"w"
,"a"
,"r+"
,"w+"
,"a+"
) for a given task.Read file content in different ways and control the cursor position with
seek()
.
Creating files to work with#
Before we begin, we need a few text files that we can use for practice later.
The code below will create these files for you.
At this stage, you do not need to understand how the code works - just run it once to generate the files.
Afterward, try opening the files and take a quick look at their content.
By the end of this lesson, you will be able to come back to this code and fully understand what it does.
# write to data.txt
with open("data.txt", "w", encoding="utf-8") as f:
f.write("This is a small text file.\n")
f.write("It has a few lines of content.\n")
f.write("Each line ends with a newline character.\n")
# write to example.txt
with open("example.txt", "w", encoding="utf-8") as f:
f.write("abcdefg\n")
f.write("hijklmn\n")
f.write("opqrstu\n")
f.write("vwxyz")
# write to poem.txt
with open("poem.txt", "w", encoding="utf-8") as f:
f.write("Roses are red\n")
f.write("Violets are blue\n")
f.write("Sugar is sweet\n")
f.write("And so are you\n")
f.write("\n")
f.write("The end")
Reading from and writing to files in Python#
Working with files is one of the most common tasks in programming. Data is often stored in files, and your program may need to read from these files or write new information back.
Opening files#
The built-in function open()
is used to open a file.
f = open("data.txt", "r")
content = f.read()
print(content)
f.close()
This is a small text file.
It has a few lines of content.
Each line ends with a newline character.
"r"
means read mode..read()
reads the file content as one string.Important: When you use
open()
like this, you must remember to call.close()
. If you forget, the file stays open in the background - and when writing, some data may remain in the buffer and never be saved properly, which can leave the file incomplete or corrupted.
Using with open (recommended)#
The safer way is to use a context manager. Python will then automatically close the file when you are done.
with open("data.txt", "r") as f:
content = f.read()
print(content)
This is a small text file.
It has a few lines of content.
Each line ends with a newline character.
with open(...) as f:
is the best practice in Python.It makes code cleaner and prevents errors.
Encoding#
When working with text files, it is good practice to always specify the file encoding.
By default, Python will use your operating system’s preferred encoding, which may differ across platforms (for example, UTF-8 on most Unix systems but CP-1252 on some Windows setups).
If you do not specify the encoding, text containing special characters (such as æ, ø, å) may not be read correctly, or you might get a UnicodeDecodeError
.
The safest choice is to always write your file operations with an explicit encoding, most commonly UTF-8. UTF-8 is the standard text encoding on the web and on most modern systems, and it can represent all characters in the Unicode standard. By explicitly setting encoding="utf-8"
, you make sure that your code behaves consistently across different computers and operating systems - even if their defaults are different.
with open("data.txt", "r", encoding="utf-8") as f:
content = f.read()
This way, you avoid problems such as:
Files containing special characters (æ, ø, å, or accented letters) not being read correctly.
Code working on your computer but failing with
UnicodeDecodeError
on someone else’s machine.Subtle errors where characters are silently replaced or corrupted because the wrong encoding was assumed.
Using encoding="utf-8"
is therefore considered best practice in modern Python programming.
File modes in open()
#
When you use open()
, the mode
parameter tells Python how you want to use the file - for reading, writing, appending, or a combination. The table below shows the most common modes.
Mode |
Meaning |
Behavior |
---|---|---|
|
Read |
File must exist. |
|
Write |
Creates a new file or truncates (empties) an existing one. |
|
Append |
Creates a new file if it doesn’t exist; otherwise writes at the end. |
|
Read and write |
File must exist. Cursor starts at the beginning. Reading/writing works from current position. Does not truncate. |
|
Write and read |
Creates a new file or truncates an existing one. Always starts with an empty file. |
|
Append and read |
File is opened for reading, but all writes go to the end. Creates if missing. |
"r+"
vs. "w+"
explained#
This is often confusing - here’s the difference.
Let us first look at the example.txt
file:
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
abcdefg
hijklmn
opqrstu
vwxyz
If we use "r+"
:
# r+ → requires file to exist, does not truncate
with open("example.txt", "r+", encoding="utf-8") as f:
f.write("HELLO")
Only the first characters are overwritten; the rest remains:
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
HELLOfg
hijklmn
opqrstu
vwxyz
If we instead use "w+"
:
# w+ → creates or truncates the file
with open("example.txt", "w+", encoding="utf-8") as f:
f.write("HELLO")
Any previous content is gone:
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
HELLO
Reading examples#
Read entire file#
Reads the whole file into one string. Useful for small files, but not memory-efficient for very large ones.
with open("poem.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
Roses are red
Violets are blue
Sugar is sweet
And so are you
The end
Read line by line#
Iterates through the file line by line. This is memory-friendly and often the best way when working with larger files.
with open("poem.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip())
Roses are red
Violets are blue
Sugar is sweet
And so are you
The end
The strip()
method removes any leading or trailing whitespace, such as the newline character \n
at the end of each line.
Removing the newline is useful because otherwise print()
will add its own line break, resulting in unwanted blank lines in the output.
This ensures the text looks clean and properly formatted when printed.
Read into a list#
Stores all lines in a list, where each element is one line (including \n
). Convenient if you need random access to specific lines.
with open("poem.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
print(lines)
['Roses are red\n', 'Violets are blue\n', 'Sugar is sweet\n', 'And so are you\n', '\n', 'The end']
Writing examples#
Write (overwrite)#
Opens the file in "w"
mode, which creates a new file or truncates (clears) the old one. Any existing content is lost.
with open("output.txt", "w", encoding="utf-8") as f:
f.write("First line\n")
f.write("Second line\n")
Append#
Opens the file in "a"
mode, which keeps the old content and adds new lines at the end of the file.
with open("output.txt", "a", encoding="utf-8") as f:
f.write("This is added at the end.\n")
Cursor and seek()
#
The file has a cursor (position).
After
f.read()
, the cursor is at the end → a newf.read()
returns an empty string.Reset the cursor with
f.seek(0)
.
with open("data.txt", "r", encoding="utf-8") as f:
print(f.read()) # reads all
f.seek(0)
print(f.read()) # reads again
This is a small text file.
It has a few lines of content.
Each line ends with a newline character.
This is a small text file.
It has a few lines of content.
Each line ends with a newline character.
Changing the index value in seek()
will change the starting position:
with open("data.txt", "r", encoding="utf-8") as f:
f.seek(1)
print(f.read()) # reads from index 1
his is a small text file.
It has a few lines of content.
Each line ends with a newline character.
Exercises#
Exercise 1: Read and print#
Open poem.txt
, read the content and print it.
Do it first with open()
+ close()
, then rewrite it using with open
.
Solution
Read using open()
and close()
:
f = open("poem.txt", "r", encoding="utf-8")
content = f.read()
f.close()
print(content) # prints the entire file content
Read using with open
(recommended):
with open("poem.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content) # prints the entire file content
Exercise 2: Count lines#
Count how many lines are in poem.txt
and print the result.
Solution
You can count the number of lines in poem.txt
like this:
with open("poem.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
num_lines = len(lines)
print("Number of lines:", num_lines)
This will print the exact number of lines in the file.
Tip: If you want to count only non-empty lines, add a condition:
with open("poem.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
num_nonempty = len([line for line in lines if line.strip()])
print("Number of non-empty lines:", num_nonempty)
In this version, line.strip()
removes whitespace.
If the line is not empty after stripping, it evaluates to True
in a condition, so the line is counted.
If the line is empty (after stripping), it evaluates to False
and is ignored.
This way you can skip blank lines and only count lines with actual content.
Exercise 3: Find a word#
Ask the user for a word and print which line numbers in poem.txt
contain that word.
Hint: Use input()
to ask the user which word to search for.
Solution
Find a word in poem.txt
(case-insensitive):
# Ask the user which word to search for
search_word = input("Which word do you want to search for? ")
# Keep track of whether we find the word or not
found_any = False
line_number = 1 # start counting lines from 1
# Open the file and go through it line by line
with open("poem.txt", "r", encoding="utf-8") as f:
for line in f:
# Make the search case-insensitive
if search_word.lower() in line.lower():
print(f"Line {line_number}: {line.strip()}")
found_any = True
line_number += 1 # move to the next line
# If no matches were found, tell the user
if not found_any:
print(f'The word "{search_word}" was not found in the file.')
word.lower() in line.lower()
makes the search case-insensitive, so “Red” matches “red”.line.strip()
removes the newline at the end before printing.
Exercise 4: Write a shopping list#
Ask the user for three shopping items and write them to shopping.txt
.
Solution
Write a shopping list with three items:
# Ask the user for three shopping items
items = []
for i in range(3):
item = input(f"Enter item {i+1}: ")
items.append(item)
# Write the items to shopping.txt, one per line
with open("shopping.txt", "w", encoding="utf-8") as f:
for item in items:
f.write(item + "\n")
print("Your shopping list has been saved to shopping.txt")
print("The list contains:")
with open("shopping.txt", "r", encoding="utf-8") as f:
print(f.read())
We use a loop to collect three items from the user and store them in a list.
"w"
mode creates (or overwrites) the file.Each item is written on its own line, ending with
\n
.After saving, we print back the items to confirm what the list contains.
Exercise 5: Append to note#
Ask the user for a short note and append it to notes.txt
.
Solution
Append a note to notes.txt
:
# Ask the user for a short note
note = input("Enter a short note: ")
# Append the note to notes.txt
with open("notes.txt", "a", encoding="utf-8") as f:
f.write(note + "\n")
print(f'Your note "{note}" has been saved to notes.txt')
print("notes.txt now contains:")
with open("notes.txt", "r", encoding="utf-8") as f:
print(f.read())
"a"
mode appends text to the end of the file instead of overwriting it.Each new note is written on its own line.
Key Points#
Use
with open(..., encoding="utf-8")
to handle files safely and consistently.File modes (
"r"
,"w"
,"a"
, plus+
) control whether you read, write, or append - and if old content is kept or erased.Files can be read all at once, line by line, or into a list, depending on your needs.
The file cursor moves as you read/write; use
.seek()
to change its position.