Reading Files Line-by-Line with a for Loop
read() loads an entire file into a single string, including all newline characters, and exhausts the file handle resource after one call.
Try it: Reading and Writing Text Files
How open() returns a file object with a position pointer, how read(), read(n), readline(), readlines() and for line in fh advance it (and return '' at the end), how 'w' and 'a' modes change the file, and why a closed file (after close() or a with block) can no longer be read.
How it works
- open(name, 'r') starts the pointer at 0; 'w' empties the file first; 'a' starts at the end.
- read() returns everything from the pointer to the end; read(n) at most n characters; readline() up to and including the next \n; each moves the pointer past what it returned.
- At the end of the file every read returns '' (an empty string), which is how loops know to stop; for line in fh reads line by line the same way.
- write() text waits in a buffer and reaches the file when it is closed (or the program ends); reading a 'w'/'a' file or writing an 'r' file raises io.UnsupportedOperation.
- close(), or leaving a with block, closes the file; any further read raises ValueError: I/O operation on closed file.
Default run (10 steps): Ready: notes.txt holds 4 lines (51 characters). Nothing is open yet. … Finished. notes.txt now holds "From: stephen\nSubject: meeting\nFrom: louis\nThanks!\n".
Simplified: The lab's own small Python interpreter runs a fixed, hand-written script (you choose the variant and the values, never the code); nothing is executed as real Python. Every script was run in CPython 3.12 with the same inputs and the lab reproduces its output and error messages. One virtual text file with \n line endings (as on Linux/macOS), positions counted in characters (ASCII only), and a write buffer that is only flushed by close() or the end of the program.
Loading the simulation…
One Read, One Position
A file on disk can contain much more data than your program should load into memory at once. Python offers two important strategies: read the complete file into one string with read(), or iterate through the file one line at a time with a for loop. The key difference is how much data is held in memory and how the file's current position changes while it is being read.
What do you think happens?
A file contains three lines. After read() is called once without a size argument, what will a second read() call on the same file handle return?
Reveal answer
An empty string
A complete read starts at the current position and continues to the end of the file. Afterward, the file handle's position is already at the end, so another read() has no remaining data to return.
What read() Returns
Calling read() without a size argument reads from the current file position through the end of the file. Python returns the complete contents as one string, including the newline characters that separate lines. Assign that returned string to a variable immediately. The variable preserves the data, while the file handle's position continues to move.
file_handle = open("notes.txt")
contents = file_handle.read()
print(contents)- 1The file handle begins with its position at the beginning of the file.
- 2The
read()call obtains all remaining file contents and returns them as one string. - 3Assigning the result to contents preserves the returned string for later processing.
- 4After the complete read, the file position is at the end.
open()creates a connection to the file.read()loads the complete remaining contents into contents.- The string in contents includes the file's newline characters.
Common mistake Calling read() twice and expecting the complete file both times.
What it looks likefirst_contents = file_handle.read() second_contents = file_handle.read()Why it failsThe first complete read moves the position to the end of the file, so the second call has no remaining data.
Do this insteadAssign the first read() result immediately and reuse that variable when you need the contents again.
Common mistake Assuming the file handle itself contains all file data.
What it looks likeTreating file_handle as though it were the text stored in the file.
Why it failsThe file handle is a connection to the file on disk. It maintains a reading position, but it does not contain the file's contents.
Do this insteadUse read() to obtain a complete string, or iterate over the handle to fetch lines incrementally.
Following the File Loop
A for loop over a file handle causes Python to fetch the next line during each iteration. The open function creates the connection but does not pull the entire file into memory. The loop body runs once for each line, and the loop variable receives that line, including its newline character when the line has one.
In this pattern, line is not the entire file. On the first iteration it refers to the first line, on the next iteration it refers to the next line, and so on. After a line has been processed, it can be discarded before the next line is fetched. The loop therefore supports processing a very large file without loading all of its contents into one string.
Newline Boundaries
A line variable normally includes the newline character at the end of that line. That character is how Python represents the boundary between one line and the next, and the for loop does not remove it when placing the line in the loop variable. The complete string returned by read() also includes newline characters, but it contains all of them in one string rather than one line variable at a time.
Using repr() in this demonstration makes the newline character visible in the displayed representation. For a line that ends normally, the representation shows the newline as part of the string. The final line may not have a newline character if the file does not end with one, so the loop variable's ending characters depend on the file's actual contents.
Choosing by File Size
| Strategy | Data held during processing | Best fit |
|---|---|---|
| read() | The complete remaining file in one string | A file small enough to fit in available RAM |
| for line in file_handle | One line at a time | Large files or processing where memory efficiency matters |
Choose the reading strategy according to file size and available memory.
Selecting a Strategy
Choose a reading strategy for a file that is 1 GB in size when the program has only a smaller amount of available RAM.
- 1Estimate what read() would require
read()attempts to place the complete file contents into one string, so the file must fit in available memory. - 2Compare the file with available memory
A 1 GB file requires at least 1 GB of free memory according to the source guidance, which is not available in this situation.
- 3Select incremental processing
Iterate over the file handle with a for loop so each line is read, processed, and then discarded before the next line arrives.
Use a for loop over the file handle rather than read().
Mistakes in File Loops
Common mistake Using read() for a file that may not fit in available RAM.
Why it failsread()loads the entire file into a single string, so memory use grows with the file size.Do this insteadUse a for loop over the file handle to keep only the current line in memory.
Common mistake Thinking that opening a file has already loaded all its contents.
Why it failsThe file handle is a connection to the file on disk, not a container holding all file data.
Do this insteadRemember that iteration triggers the fetching of each next line.
Common mistake Assuming a line variable never contains a newline character.
Why it failsEach iteration normally includes the line's newline character.
Do this insteadAccount for the newline when processing or displaying a line.
Common mistake Calling read() again after the complete contents have already been saved.
Why it failsThe file position is at the end after the first complete read, so the later call returns an empty string.
Do this insteadReuse the variable holding the first read() result.
Practice the Decision
A program needs to count the lines in a very large file. Write the file-reading pattern that keeps memory use low, and explain what the loop variable contains during one iteration.
Hints
- Use a for loop directly with the file handle.
- Increment a counter inside the loop.
- The loop variable contains one line, normally including its newline character.
A small file must be used several times after it is opened. Decide whether read() is suitable, and state what should happen immediately after the call to read().
Hints
- Consider whether the complete file can fit in available RAM.
- Assign the returned string to a variable immediately.
- Do not expect a second complete read from the same position.
Key Takeaways
- 1
read()returns the complete remaining file contents as one string, including newline characters. - 2After a complete
read(), the file position is at the end, so anotherread()on that handle returns an empty string. - 3A file handle is a connection to the file on disk and maintains a reading position; it does not contain all file data.
- 4A for loop over a file handle fetches one line per iteration, normally including that line's newline character.
- 5Use
read()for files that fit in available RAM and line-by-line iteration when memory efficiency is important, especially for large files.
At a glance
read()loads a complete file into one string and moves the file position to the end.- A second
read()on the same handle returns an empty string because no data remains at the current position. - The file handle is a connection with a position pointer, not a copy of the file's contents.
- A for loop reads one line at a time and normally keeps only the current line in memory.
- Choose
read()for suitably small files and line-by-line iteration for large files or memory-sensitive processing.