How to read a text file in Python

Reading text files in Python is easy. Learn different methods, get useful tips, see real-world examples, and find solutions to common errors.

How to read a text file in Python
Published on: 
Thu
Feb 5, 2026
Updated on: 
Tue
Feb 10, 2026
The Replit Team Logo Image
The Replit Team

To read a text file in Python is a core skill for any developer. It lets you process data, parse configurations, and automate tasks with just a few lines of code.

You'll learn several techniques to handle files, from the basic open() function to more advanced methods. You'll also get practical tips, see real-world applications, and receive advice to debug common issues.

Basic file reading with open() and read()

file = open('example.txt', 'r')
content = file.read()
print(content)
file.close()--OUTPUT--Hello, World!
This is a sample file.
Python file handling is easy.

The open() function is your starting point, creating a file object to work with. Using the 'r' mode is a key safeguard—it signals your intent to only read the file, which prevents accidental writes.

The read() method then consumes the entire file and stores it as a single string. While simple, this approach loads everything into memory at once, so it’s not the most efficient choice for very large files. Finally, calling close() is essential to release the file handle and free up system resources.

Common file reading techniques

Beyond the basic read() method, Python provides more memory-efficient and robust techniques for reading files line by line or with automatic resource management.

Reading a file line by line with a for loop

file = open('example.txt', 'r')
for line in file:
print(line.strip()) # strip() removes newline characters
file.close()--OUTPUT--Hello, World!
This is a sample file.
Python file handling is easy.

Iterating directly over the file object is a memory-efficient way to handle files, especially large ones. Instead of loading everything at once, the for loop processes the file one line at a time.

  • Each line read from the file includes a trailing newline character.
  • You’ll want to use the strip() method to remove this character, which prevents unwanted blank lines in your output.

This approach gives you a clean, line-by-line stream of the file's content without overwhelming your system's memory.

Using readlines() to get a list of lines

file = open('example.txt', 'r')
lines = file.readlines()
print(lines)
file.close()--OUTPUT--['Hello, World!\n', 'This is a sample file.\n', 'Python file handling is easy.']

The readlines() method reads the entire file and returns its contents as a list of strings. This approach is handy when you need to access lines by their index or perform list-based operations on the file's content.

  • Just like iterating with a loop, each string in the returned list includes its original newline character (\n).
  • Because readlines() loads the whole file into memory, it’s best reserved for files that aren't excessively large.

Using with statement for safer file handling

with open('example.txt', 'r') as file:
content = file.read()
print(content)
# File is automatically closed when leaving the with block--OUTPUT--Hello, World!
This is a sample file.
Python file handling is easy.

Using the with statement is the most reliable way to handle files. It acts as a context manager, which means it automatically takes care of opening and—more importantly—closing the file for you. You don't have to worry about calling file.close() yourself.

  • Once the code inside the with block finishes, the file is closed automatically.
  • This holds true even if an error occurs, making your code safer and preventing resource leaks.

Advanced file operations

With the fundamentals down, you can gain more precise control using seek() and tell(), work with different text encodings, and manage file paths more effectively.

Reading specific portions with seek() and tell()

with open('example.txt', 'r') as file:
file.seek(7) # Move to the 7th byte in the file
partial = file.read(5) # Read 5 characters
position = file.tell() # Get current position
print(f"Read '{partial}' and now at position {position}")--OUTPUT--Read 'World' and now at position 12

The seek() and tell() methods give you precise control over file navigation, much like moving a cursor in a text editor. You can jump to any byte position and start reading from that exact spot.

  • seek() moves the file pointer to a specific byte offset. For instance, seek(7) jumps to the 7th byte.
  • tell() returns the pointer's current position, so you always know where you are in the file.

This is especially useful for parsing binary files or fixed-width data formats where you need to access specific data segments directly without reading the whole file.

Working with different file encodings

with open('unicode_example.txt', 'r', encoding='utf-8') as file:
content = file.read()
print(f"File contains {len(content)} characters")
print(content[:20]) # First 20 characters--OUTPUT--File contains 45 characters
こんにちは, 世界! Hello

Text files are stored as bytes, and the encoding parameter in the open() function tells Python how to translate those bytes into readable characters. If you don't specify an encoding, Python guesses based on your system's default, which can lead to garbled text or errors.

  • Specifying encoding='utf-8' is a best practice. It's a universal standard that supports characters from nearly all languages.
  • If you ever see a UnicodeDecodeError, it’s a strong hint that the file's encoding doesn't match what you've specified.

Using pathlib for modern file operations

from pathlib import Path

file_path = Path('example.txt')
text = file_path.read_text(encoding='utf-8')
print(f"File exists: {file_path.exists()}")
print(text[:15]) # First 15 characters--OUTPUT--File exists: True
Hello, World!
T

The pathlib module offers a modern, object-oriented approach to file system paths. Instead of manipulating strings, you create Path objects that come with helpful methods built right in. This makes your code cleaner and more readable.

  • The read_text() method is a convenient shortcut. It handles opening, reading, and closing the file for you, returning the entire content as a string.
  • You also get other handy tools, like the exists() method, which lets you quickly check if a file is present before you try to use it.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. Describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.

For the file reading techniques we've explored, Replit Agent can turn them into production-ready tools:

  • Build a log file analyzer that reads server logs line by line to identify and count specific error types.
  • Create a configuration parser that processes .ini or .env files and loads settings into a structured format.
  • Deploy a data extraction utility that uses seek() and tell() to pull specific records from large binary files without loading them into memory.

Describe your app idea, and Replit Agent will write the code, test it, and fix issues automatically, all from your browser.

Common errors and challenges

Even simple file operations can trip you up, but most errors fall into a few common categories you can easily manage.

Handling FileNotFoundError gracefully

A FileNotFoundError is exactly what it sounds like—Python can't find the file you've asked for. You can handle this gracefully in a couple of ways.

  • Use a try...except block to catch the error. This lets your program continue running, perhaps by creating the file or alerting the user.
  • Proactively check if the file exists before trying to open it. The pathlib module's exists() method is perfect for this.

Resolving UnicodeDecodeError with proper encoding

You'll hit a UnicodeDecodeError when Python can't translate the file's bytes into text using the specified encoding. While setting encoding='utf-8' is a robust default, it's not a silver bullet.

If you encounter this error, it means the file was saved with a different encoding. You may need to find out the correct one—common culprits include 'latin-1' or 'cp1252' for files originating from older systems—and pass it to the open() function.

Understanding file position when reading multiple times

It's helpful to think of a file object as having a cursor that marks your current position. After you read a file, that cursor is left at the very end.

If you try to call read() or readlines() a second time on the same file object, you'll get an empty result because there's nothing left to read. To read the file again from the beginning, you must first reset the cursor by calling file.seek(0).

Handling FileNotFoundError gracefully

Handling FileNotFoundError gracefully

A FileNotFoundError is one of the most common runtime errors you'll encounter. It happens when your code tries to open a file that doesn't exist, which can abruptly crash your program if it's left unhandled. The following code demonstrates this exact problem.

def read_config(filename):
file = open(filename, 'r')
content = file.read()
file.close()
return content

# Will crash if config.txt doesn't exist
config = read_config('config.txt')
print("Configuration loaded")

The read_config function calls open() without first confirming the file is there. If config.txt is missing, the program stops dead. The following example shows how to handle this situation gracefully so your program can continue running.

def read_config(filename):
try:
with open(filename, 'r') as file:
return file.read()
except FileNotFoundError:
print(f"Config file {filename} not found, using defaults")
return "default_setting=True"

config = read_config('config.txt')
print("Configuration loaded")

The improved function wraps the file operation in a try...except block, which is a robust way to handle optional files like configurations. It prevents your program from crashing if the file doesn't exist.

  • The try block attempts to open and read the file as usual.
  • If a FileNotFoundError occurs, the except block runs instead, printing a message and returning a default value so the program can continue.

Resolving UnicodeDecodeError with proper encoding

Resolving UnicodeDecodeError with proper encoding

A UnicodeDecodeError occurs when Python can't interpret a file's bytes using the default system encoding. This often happens with text containing international characters or symbols, leading to garbled output or a program crash.

The following code demonstrates what happens when you try to read a file saved with one encoding without telling the open() function which one to use.

# Trying to read a UTF-8 file with default encoding
with open('international_text.txt', 'r') as file:
content = file.read() # May raise UnicodeDecodeError
print(content)

The open() function defaults to your system's encoding, which may not be able to interpret the file's characters. This mismatch triggers the error. The following example demonstrates how to handle this correctly.

# Specifying the correct encoding
with open('international_text.txt', 'r', encoding='utf-8') as file:
content = file.read()
print(content)

The solution is to explicitly tell Python which encoding to use. By adding the encoding='utf-8' parameter to the open() function, you provide the correct map for translating the file's bytes into readable text, ensuring characters are displayed properly.

  • This is the most common fix for files containing non-ASCII characters, like emojis or text in different languages.
  • Always specifying an encoding is a best practice that makes your code more portable and reliable across systems.

Understanding file position when reading multiple times

When you read from a file, Python uses an internal pointer to track your position. After a read operation, this pointer remains where it left off. Attempting to read again will only give you the remaining content, not the whole file.

The code below demonstrates what happens when you call readline() and then read() on the same file object. Notice how the second read operation returns less content than you might expect because the pointer has already moved past the first line.

with open('example.txt', 'r') as file:
first_line = file.readline()
print(f"First line: {first_line.strip()}")

# Trying to read the whole file again
all_content = file.read()
print(f"All content has {len(all_content)} characters") # Fewer than expected

The read() call only captures what's left after readline() has already consumed the first line, resulting in an incomplete read. To get the full content every time, you need to reset the file's position, as shown in the following example.

with open('example.txt', 'r') as file:
first_line = file.readline()
print(f"First line: {first_line.strip()}")

# Reset the file position to the beginning
file.seek(0)
all_content = file.read()
print(f"All content has {len(all_content)} characters")

The solution is to manually reset the file's internal pointer. By calling file.seek(0), you move the pointer back to the beginning of the file, which lets you read its entire contents again from the start.

  • This is crucial when you need to perform multiple read operations on the same file object.
  • Without resetting, subsequent reads will only capture content from the pointer's last position, leading to incomplete data.

Real-world applications

Now that you have the tools, you can solve real-world problems like parsing CSV files or analyzing logs with the re module.

Processing CSV files for data analysis

Reading structured data from a CSV file is a common task, and Python's csv module provides an efficient way to iterate over rows and extract the data you need for analysis.

import csv

with open('sales_data.csv', 'r') as file:
csv_reader = csv.reader(file)
headers = next(csv_reader)
total_sales = 0
for row in csv_reader:
total_sales += float(row[2])
print(f"Total sales: ${total_sales:.2f}")

The csv module is perfect for handling structured data. It creates a csv.reader object that lets you loop through the file row by row, where each row is conveniently parsed into a list of strings.

  • The next() function is used to read and discard the header line, so the loop only processes the data records.
  • Inside the loop, you can access specific columns by their index, like row[2], and convert them to the right data type for calculations.

Analyzing log files with re for error monitoring

The re module is a powerful tool for searching through log files line by line, letting you identify and count specific error messages with regular expressions.

import re
from collections import Counter

error_pattern = r"ERROR: (.*)"
errors = []

with open('application.log', 'r') as log_file:
for line in log_file:
match = re.search(error_pattern, line)
if match:
errors.append(match.group(1))

error_counts = Counter(errors)
print(f"Found {len(errors)} errors. Most common:")
for error, count in error_counts.most_common(3):
print(f"{count} occurrences: {error}")

This script combines regular expressions with the collections module to perform a quick log analysis. It reads application.log line by line, using re.search() to find lines matching the error_pattern. When a match is found, it extracts the specific error message using match.group(1).

  • All extracted errors are collected into a list.
  • The Counter object then efficiently tallies the occurrences of each unique error.
  • Finally, most_common(3) retrieves the top three recurring issues, giving you a focused summary of the most frequent problems.

Get started with Replit

Turn your new skills into a real application. Describe your idea to Replit Agent, like "a CSV parser that totals sales data" or "a log analyzer that counts specific error types."

It writes the code, tests for errors, and deploys your app from a single prompt. Start building with Replit.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.