COMPUTER PROGRAMMING 1 (PYTHON) • FILES & DATA I/O

Reading Text Files — I can read a text file using with open(...) and process it line by line safely.

Learn to open, read, and process text files safely using Python's with statement and line-by-line iteration.

Historical Context & Motivation

Programs have always needed a way to interact with data stored outside of memory. In the earliest days of computing, data lived on physical punch cards, and programmers had to deal with complicated hardware-level commands just to read a single row of holes. As operating systems matured, the concept of a file became the standard way to package and store information on disk. Every application you use today—from web browsers to video games—reads and writes files constantly.

Python's approach to file handling was shaped by decades of lessons learned from older languages like C, where forgetting to close a file could leak system resources and crash programs. Python introduced the with statement (also called a context manager) to make file I/O safer and more readable. This was a huge improvement because it guaranteed that files would be properly closed, even if an error occurred during processing.

1960s
Punch Cards & Tape
Early programs read data from physical punch cards and magnetic tape, requiring low-level hardware commands to access stored information.
1972
C Language File I/O
The C programming language introduced fopen() and fclose() functions. Forgetting to call fclose() led to resource leaks—a common and frustrating bug.
1991
Python 1.0 Introduces open()
Guido van Rossum created Python with a built-in open() function, making file operations simpler than in C or Java.
2005
PEP 343 — The 'with' Statement
Python 2.5 introduced the with statement, enabling automatic resource management. Files opened with with open(...) are guaranteed to close, even if an error occurs.
2020s
Modern Python Best Practice
Today, with open(...) is the universally recommended pattern for file I/O in Python, used in data science, web development, and automation.

The central question that drives this lesson is straightforward: how can you reliably open a text file, read its content line by line, and guarantee that the file is properly closed when you are done? Understanding this pattern is essential because almost every real-world program needs to load data from external files at some point.

Core Principles & Definitions

Before diving into code, you need to understand a few foundational ideas about how Python handles files. These principles will help you understand not just what the code does, but why the code is written a certain way.

1

File Object

When you call open(), Python creates a file object that acts as your connection to the data on disk. Think of it as a handle you hold while reading.
2

The with Statement

The with keyword creates a context manager that automatically closes the file when the indented block finishes, even if an error occurs.
3

Read Mode ('r')

Files can be opened in different modes. The default mode 'r' means read-only. You can look at the data, but you cannot change or delete it.
4

Line-by-Line Iteration

A file object is iterable—you can loop over it with a for loop, and each pass gives you one line of text. This is memory-efficient for large files.
5

The .strip() Method

Each line from a file includes a hidden newline character (\n) at the end. Calling .strip() removes this trailing whitespace cleanly.
✦ KEY TAKEAWAY
Think of with open(...) like borrowing a library book with an automatic return system. The with statement is the checkout desk—it hands you the book (file object) and guarantees the book is returned (file is closed) as soon as you walk out of the building (leave the indented block), even if you trip on your way out (encounter an error).

Visual Explanation — How with open() Works

The diagram below illustrates the entire lifecycle of reading a text file in Python. Follow the flow from left to right to see how with open() opens a connection, how the for loop processes lines, and how the file is automatically closed at the end.

The top row shows the four-step lifecycle: open, enter the with block, process lines, and auto-close. The bottom section shows the syntax-highlighted code with annotations explaining each line.

Notice that the entire reading operation happens inside the indented block under the with statement. As soon as your code exits that indented block—whether it finishes normally or encounters an error—Python calls f.close() automatically. You never have to remember to close the file yourself. The for line in f loop reads one line at a time from the file, which means even a file with millions of lines will not crash your program by using too much memory.

How It Works — The Mechanics of File Reading

The open() Function

The open() function is a Python built-in that takes at least one argument—the path to the file—and returns a file object. The second argument, the mode string, tells Python what you want to do with the file. The most common modes are listed in the table below.

Common file modes in Python
ModeMeaningCreates File?Overwrites?
"r"Read (default)No — error if missingNo
"w"WriteYesYes — erases existing content
"a"AppendYesNo — adds to end
"r+"Read and WriteNo — error if missingPartial (depends on position)

Reading Methods Compared

Python gives you three main ways to read content from a file object. Each approach has trade-offs related to memory usage and convenience. The method you choose depends on how large your file is and how you need to process the data.

Three ways to read file content
MethodReturnsMemory UsageBest For
f.read()Entire file as one stringHigh — loads everythingSmall files (under 1 MB)
f.readlines()List of all linesHigh — loads everythingWhen you need all lines in a list
for line in f:One line per iterationLow — one line at a timeLarge files, line-by-line processing
💡 Why line-by-line is best
Using for line in f: is the recommended approach for most situations. It reads only one line into memory at a time, so your program can handle files of any size—even multi-gigabyte log files—without running out of memory.

Encoding: How Text Becomes Bytes

Under the hood, files store raw bytes, not characters. Python converts bytes to text using an encoding. The default encoding in modern Python is UTF-8, which supports nearly every language and special character. If you ever get garbled output, you can specify the encoding explicitly: open("data.txt", "r", encoding="utf-8").

Common Patterns for Processing Lines

Once you know how to read a file line by line, there are several common patterns you will use repeatedly. These patterns form the building blocks for almost every file-processing task in Python, from analyzing data logs to loading configuration settings.

Four essential patterns for line-by-line file processing. Pattern 1 prints every line. Pattern 2 collects lines into a list for later use. Pattern 3 uses a conditional to filter specific lines. Pattern 4 counts the total number of lines in a file.

All four patterns share the same basic structure: a with open(...) as f: wrapper around a for line in f: loop. What changes is what you do inside the loop. Pattern 1 simply prints each line. Pattern 2 builds a list so you can access lines by index later. Pattern 3 adds an if statement to filter lines that match a condition. Pattern 4 accumulates a counter to determine how many lines the file contains.

⚠️ Don't forget .strip()!
Each line read from a file ends with a newline character \n. If you print lines without calling .strip(), you will see extra blank lines in your output because print() adds its own newline on top of the one already in the string.

Worked Example — Analyzing a Grades File

Suppose you have a file called grades.txt that contains one numeric grade per line. Your task is to read the file, compute the average grade, and print the result. Here is what the file looks like:

📄 grades.txt
92 85 78 95 88 76 91
Computing the Average Grade from a File
1
Step 1 — Plan the VariablesTo compute an average, we need two pieces of information: the total sum of all grades and the count of how many grades there are. We initialize both to zero before opening the file.
total = 0 and count = 0
2
Step 2 — Open the File with 'with'We use with open("grades.txt", "r") as f: to safely open the file in read mode. The variable f now holds our file object.
with open("grades.txt", "r") as f:
3
Step 3 — Loop Through Each LineInside the with block, we write for line in f: to iterate through the file one line at a time. Each line is a string like "92\n". We call line.strip() to remove the trailing newline, then convert it to an integer with int().
grade = int(line.strip())
4
Step 4 — Accumulate the Sum and CountFor each line, we add the grade to our running total and increment the count by one. After the loop finishes, total will hold the sum of all grades (92 + 85 + 78 + 95 + 88 + 76 + 91 = 605) and count will be 7.
total += grade and count += 1
5
Step 5 — Compute and Print the AverageAfter the with block ends (the file is now closed), we compute the average by dividing total by count. The result is 605 ÷ 7 ≈ 86.43.
average = total / count → 86.43

Here is the complete program:

💻 Complete Code
total = 0 count = 0 with open("grades.txt", "r") as f: for line in f: grade = int(line.strip()) total += grade count += 1 average = total / count print(f"Average grade: {average:.2f}")

with open() vs. Manual open/close — Strengths & Limitations

You can technically open files without the with statement by calling f = open("data.txt") and later f.close(). However, this older approach is error-prone and is not recommended. Let's compare both approaches side by side.

Comparing safe vs. manual file handling
Featurewith open() ✅Manual open/close ⚠️
File guaranteed to closeYes — automatic on block exitOnly if you remember to call f.close()
Safe during errorsYes — closes even if an exception occursNo — if an error occurs before f.close(), file stays open
Lines of codeFewer — no separate close() call neededMore — requires explicit f.close()
ReadabilityClear indentation shows file scopeHarder to see where file is in use
Industry standardYes — PEP 8 recommendedConsidered outdated
✦ KEY TAKEAWAY
Using with open() is like wearing a seatbelt while driving. You could technically drive without one, and you might be fine most of the time—but the one time something goes wrong (an error or crash), the seatbelt (automatic close) prevents a much bigger disaster (resource leaks, corrupted data). Always use with.

Connection to Advanced File I/O

Reading plain text files line by line is your starting point, but the same foundational pattern extends to much more powerful file operations. As you advance in programming, you will encounter structured file formats and specialized libraries that build on these same principles.

From basic text files to advanced data processing
This LessonWhat Comes Next
Reading .txt filesReading .csv files with the csv module
Line-by-line iterationParsing structured data (JSON, XML)
Read mode ("r")Write mode ("w") and append mode ("a")
Single file processingProcessing multiple files with os.listdir()
Manual string processingPandas DataFrames for large-scale data analysis

The beauty of the with statement is that it is not limited to files. Python's context manager protocol works with database connections, network sockets, and even custom classes. Once you understand the pattern of "open a resource, use it, close it automatically," you have a mental model that will serve you across every area of software development.

🔮 Error Handling Preview
What happens if the file does not exist? Python raises a FileNotFoundError. In future lessons, you will learn to handle this gracefully using try / except blocks. For now, just make sure the file you are trying to open actually exists in the same folder as your Python script.

Practice Problems

Work through these five problems to reinforce your understanding. Each one builds on the concepts covered in this lesson. Try writing the code yourself before checking the answer.

PROBLEM 1 — CONCEPTUAL
Explain in your own words why using with open(...) as f: is safer than using f = open(...) followed by f.close(). What specific problem does the with statement prevent?
PROBLEM 2 — BASIC
Write a short Python program that opens a file called names.txt and prints every line with the line number in front of it. For example, if the file contains "Alice" on line 1, it should print 1: Alice.
PROBLEM 3 — INTERMEDIATE
A file called temperatures.txt contains one temperature reading per line (as a decimal number). Write a program that reads the file and prints the highest temperature found. Do not use f.readlines()—process the file line by line.
PROBLEM 4 — APPLIED
You are building a simple word-count tool. Given a file called essay.txt, write a program that counts the total number of words in the file. Assume words are separated by spaces. Print the result as: "Total words: X".
PROBLEM 5 — CRITICAL THINKING
A file called scores.txt has lines in the format "Name,Score" (for example, "Alice,95"). Write a program that reads the file and prints only the names of students who scored 90 or above. What would happen if a line were blank or improperly formatted? How might you handle that?

Lesson Summary

In this lesson, you learned to read text files safely in Python using the with open() pattern, which creates a context manager that automatically closes the file when the indented block ends. You saw that Python's open() function returns a file object, and that the default read mode ("r") lets you access the data without risk of accidentally changing it.

The most memory-efficient way to process a file is line-by-line iteration using for line in f:, which reads only one line at a time. You also learned to use .strip() to remove trailing newline characters, and you practiced four essential patterns: printing lines, collecting into a list, filtering by condition, and counting lines. These patterns are the building blocks for all future file-processing tasks in Python.

Varsity Tutors • Computer Programming 1 (Python) • Reading Text Files