Python online course

How to Read Text Files in Python

Learn how to open, read, iterate through, and safely close text files in Python with practical examples.

What You Need Before Starting

This lesson assumes you know Python variables, strings, function calls, methods, for loops, and how to create or write a simple text file. You should also understand that a relative file path is interpreted from the program's current working directory.

Suppose new_file.txt contains:

Hello from Python.
Reading files is useful.

Opening a Text File for Reading

Python's open() function opens a file and returns a file object. A file object provides methods and iteration for working with the file's contents.

Pass the filename as the first argument and the opening mode as the second argument:

fr = open("new_file.txt", "r")

The "r" mode means read mode. It opens an existing file so that Python can read its contents. Read mode does not create a missing file. If Python cannot find the file, it normally raises FileNotFoundError.

ModeMeaningRequires existing fileCan modify file
rRead an existing fileYesNo
wWrite a file; usually replaces existing contentsNoYes
aAppend data to the end of a fileNo; Python can create itYes

This lesson focuses on r. The other modes are included as a reminder that opening mode determines what operations are allowed.

File paths

If the file is not in the current working directory, provide a relative or absolute path. For example:

fr = open("data/new_file.txt", "r")

For text files whose encoding is known, specifying it explicitly makes the program more predictable:

fr = open("new_file.txt", "r", encoding="utf-8")

Reading the Entire File with read()

The file object's read() method returns all remaining file contents as one string. Assign that string to a variable and display it with print():

fr = open("new_file.txt", "r")
text = fr.read()
print(text)
fr.close()

For a small file, this is a straightforward approach. The complete text is stored in the text variable.

The file cursor

A file cursor is the current position in a file. Reading starts at the cursor and advances it. After read() consumes the remaining content, the cursor is at the end of the file.

fr = open("new_file.txt", "r")
first_read = fr.read()
second_read = fr.read()

print(first_read)
print(repr(second_read))  # ''
fr.close()

The second call returns an empty string because there is no unread content left. To read the contents again, reopen the file or move the cursor back to the beginning with fr.seek(0):

fr.seek(0)
again = fr.read()

Closing an Explicitly Opened File

Calling open() uses a file resource. When all reading is complete, call the file object's close() method to release that resource:

fr = open("new_file.txt", "r")
text = fr.read()
print(text)
fr.close()

Close the file only after all operations that need it are complete. After closing, do not try to read from or iterate over that file object.

Reading One Line at a Time

A file object is iterable, which means a loop can obtain values from it one at a time. Iterating over a text file produces one line per loop iteration.

fr = open("new_file.txt", "r")
line_number = 1

for line in fr:
    print(line_number, "line:", line, end="")
    line_number += 1

fr.close()

Here, line_number labels each line. The counter increases after each iteration.

Why use end=""?

Lines read from a text file commonly retain their trailing newline character, represented as \n. The print() function normally adds another newline. Without end="", those two newline characters can produce an extra blank line between outputs.

Another option is to remove surrounding whitespace before printing:

with open("new_file.txt", "r") as fr:
    for line_number, line in enumerate(fr, start=1):
        print(line_number, "line:", line.rstrip())

rstrip() removes trailing whitespace, including the line-ending character. Use it when removing that whitespace is appropriate for your output.

Choosing a Reading Approach

ApproachResultBest useMemory consideration
read()One string containing all remaining contentSmall files or situations where all text is needed at onceLoads the remaining content into memory
for line in file_objectOne line per iterationIncremental processing, filtering, counting, or inspecting large filesGenerally more memory-friendly because it does not load the whole file at once
readline()The next single line as a stringWhen code needs explicit control over individual readsTypically memory-friendly; repeated calls advance the cursor

Choose read() when the file is small or your operation needs the complete text. Choose line-by-line iteration when processing can happen incrementally, especially for larger files.

All these methods advance the file cursor. If content has already been consumed, reopen the file or reposition the cursor with seek(0) before rereading it.

Preferred File Handling with with

The preferred modern pattern is a with statement:

with open("new_file.txt", "r") as fr:
    text = fr.read()

print(text)

The with statement uses a context manager. A context manager manages setup and cleanup around a block of code. When execution leaves the block, Python closes the file automatically, including when an error occurs inside the block.

Whole-file reading with automatic cleanup

with open("new_file.txt", "r", encoding="utf-8") as fr:
    text = fr.read()

print(text)

The variable text remains available after the block, but the file object fr has been closed.

Line-by-line reading with automatic cleanup

with open("new_file.txt", "r", encoding="utf-8") as fr:
    for line_number, line in enumerate(fr, start=1):
        if line.strip():
            print(line_number, line.strip())

enumerate() supplies both a counter and the current line. start=1 makes the first line number 1. The condition ignores empty or whitespace-only lines, while strip() removes surrounding whitespace for display.

Troubleshooting File Reading

FileNotFoundError

This exception means Python could not locate the requested file. Check for:

  • A misspelled filename or extension.
  • A file stored in a different folder.
  • A relative path based on an unexpected current working directory.

Confirm the file's location and provide the correct relative or absolute path. You can also review file locations with operating-system tools or Python's path utilities.

A second read() returns ""

The first call probably moved the file cursor to the end. Save the first result, reopen the file, or call seek(0) before reading again.

Extra blank lines appear

The input line may already contain \n, and print() adds another newline. Use print(line, end="") or remove the trailing line ending with line.rstrip().

The file remains open after an error

Manual close() may not run if an exception interrupts execution. Replace the explicit open-and-close pattern with with open(...) as fr:.

Unreadable characters or decoding errors

The file may use an encoding different from the platform default. If the file's encoding is known, specify it:

with open("new_file.txt", "r", encoding="utf-8") as fr:
    text = fr.read()

Complete Examples

Display all text from a small file

with open("new_file.txt", "r") as fr:
    text = fr.read()

print(text)

This stores the entire file in one string and prints it.

Label every line

with open("new_file.txt", "r") as fr:
    line_number = 1
    for line in fr:
        print(line_number, "line:", line, end="")
        line_number += 1

This processes one line per iteration and avoids doubled blank lines.

Inspect non-empty lines in a larger file

with open("new_file.txt", "r") as fr:
    for line_number, line in enumerate(fr, start=1):
        if line.strip():
            print(line_number, line.strip())

This approach processes lines incrementally rather than loading the entire file into one string.

Key Points to Remember

  • open(filename, "r") returns a file object for reading an existing file.
  • Read mode does not create a missing file; an invalid path commonly raises FileNotFoundError.
  • read() returns all remaining content as one string and moves the cursor to the end.
  • A file object can be used in a for loop to process one line at a time.
  • Read lines often include a trailing newline character.
  • Use with open(...) so Python closes the file automatically.
  • Reopen a file or use seek(0) before rereading consumed content.

For related fundamentals, review Python strings, the for loop, and reading and writing files.