Chapters
Python114 chapters

Files and errorsChapter 81 of 114

Write Files

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

write

Python
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("first line\n")
    f.write("second line\n")

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

Output

first line
second line

write adds no newline of its own — unlike print — so you put \n where you want line breaks.

It returns the number of characters written, which is occasionally useful:

Python
with open("notes.txt", "w", encoding="utf-8") as f:
    print(f.write("hello"))

Output

5

w empties the file first

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

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

with open("notes.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

replacement

The original is gone. That happens when the file is opened, not when you write, so opening in "w" and then failing still leaves you with an empty file.

a appends

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

for line in ["two", "three"]:
    with open("log.txt", "a", encoding="utf-8") as f:
        f.write(line + "\n")

with open("log.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

one
two
three

Appending in a loop like that reopens the file each time. For anything hot, open once outside the loop.

writelines writes a list

Python
lines = ["Ada\n", "Grace\n"]

with open("names.txt", "w", encoding="utf-8") as f:
    f.writelines(lines)

with open("names.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

Ada
Grace
Python
with open("names.txt", "w", encoding="utf-8") as f:
    f.writelines(["Ada", "Grace"])

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

Output

AdaGrace

Building the text yourself is clearer:

Python
names = ["Ada", "Grace"]

with open("names.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(names) + "\n")

with open("names.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

Ada
Grace

print takes a file argument, which brings its newline handling with it:

Python
with open("report.txt", "w", encoding="utf-8") as f:
    print("Title", file=f)
    print("value:", 42, file=f)

with open("report.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

Title
value: 42

pathlib for small files

Python
from pathlib import Path

Path("short.txt").write_text("one line\n", encoding="utf-8")
print(Path("short.txt").read_text(encoding="utf-8").strip())

Output

one line

It opens, writes and closes in one call. For anything you write incrementally, use with open.

Do not overwrite until you have succeeded

Writing straight over a file means a crash halfway leaves you with neither the old contents nor the new. Write to a temporary name and rename when it is safe:

Python
import os

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

with open("data.txt.tmp", "w", encoding="utf-8") as f:
    f.write("new contents\n")

os.replace("data.txt.tmp", "data.txt")

with open("data.txt", encoding="utf-8") as f:
    print(f.read().strip())

Output

new contents

os.replace swaps the file in one step, so a reader sees either the old file or the new one and never a half-written mess.

Test yourself

2 questions

What does writelines() add between the strings?

Show the answer

Nothing — Despite the name it means 'write all these strings'. Build the text with join if you want separators.

Why write to a temporary name and then os.replace?

Show the answer

A crash halfway cannot leave you with a half-written file — The rename is a single step, so a reader sees either the old file or the new one.

Next chapter

Delete Files

Remove files and folders, and check first without a race.