Reading and writing files

Reading content

with open(path) as f:
    content = f.read()        # the entire file, as one string

For line-oriented files, two other options are often more convenient:

with open(path) as f:
    lines = f.readlines()     # a list of lines, each still ending in "\n"

with open(path) as f:
    for line in f:             # iterate the file directly, one line at a time
        print(line.strip())    # .strip() removes the trailing newline

Iterating a file object directly (the third form) is the most memory-efficient for large files — it reads one line at a time instead of loading everything at once — but for the file sizes in this course, all three approaches work fine.

content.splitlines() is another handy option: it splits content into a list of lines without the trailing "\n" on each one (unlike readlines()), which is usually what you actually want.

Writing content

with open(path, "w") as f:
    f.write("hello\n")   # write() does NOT add a newline for you -- add \n yourself
    f.write("world\n")

Unlike print(), f.write() writes exactly the string you give it — no automatic newline. If you want lines separated, you write the \n characters yourself.

A complete read-then-write example

def shout_file(in_path, out_path):
    with open(in_path) as f:
        content = f.read()
    with open(out_path, "w") as f:
        f.write(content.upper())

Two separate with blocks — one to read the input file (and let it close), one to write the output file. This is the exact shape you'll use for the read-then-transform-then-write problems ahead: read everything you need first, close that file, then open the output file and write to it.

A note on this course's file system

The problems ahead run in a sandboxed in-memory file system — files you "seed" for a test exist only for that test, and reading/writing paths like /tmp/data.txt works exactly like it would on a real filesystem, just without touching anything on your actual computer.