How to Read and Write Text Files in Python: A Complete Beginner’s Guide (2026)

Why File Handling Matters in Python

Imagine you’ve just built a Python program that asks users for their names and favourite movies. It works perfectly — until you close the terminal. The next time you run it, everything is gone.

This is the problem that file handling solves.

Every meaningful application — from a simple to-do list to a full-scale web server — needs to store and retrieve data beyond a single session. In Python, this is done by reading from and writing to files stored on your computer’s disk.

Learning how to read and write text files in Python is one of the most practical skills you can develop early in your programming journey. You’ll use it for:

  • 📝 Saving user data and application settings
  • 🔍 Reading configuration files for your programs
  • 📊 Processing data from external sources (CSV, log files)
  • 🗂️ Building simple databases for small applications
  • 🚀 Writing log files to track what your app is doing

In this complete, beginner-friendly guide, you’ll go from zero to confident — understanding every essential concept of Python file handling with clear explanations, working code examples, and real-world mini projects.

💡 Prerequisite: Before diving in, it helps to have a basic understanding of Python variables and data types and Python functions. Don’t worry if you’re just starting — every concept here is explained step by step.


What Is File Handling in Python?

File handling is the process of interacting with files stored on your computer’s secondary storage (your hard drive or SSD) using Python code.

In simple terms: it’s how your Python program talks to files — opening them, reading their content, writing new content, and closing them safely.

Python makes this remarkably easy. Unlike lower-level languages like C or Java, Python provides simple, readable built-in tools to manage files without needing external libraries.

Why Can’t We Just Use Variables?

Great question. When you store data in a Python variable, it lives in RAM (Random Access Memory) — which is temporary. The moment your program finishes running, that memory is cleared and your data disappears.

Files, on the other hand, are stored on disk (persistent storage). Data written to a file survives after the program ends, after a reboot, and after the computer is turned off.

# This data is LOST when the program ends
name = "Alice"
score = 95

# This data is SAVED permanently to disk
with open("scores.txt", "w") as file:
    file.write(f"{name}: {score}\n")

The Core Operations in File Handling

Python file handling revolves around four core operations, often remembered by the acronym CRUD:

OperationDescriptionPython Action
CreateMake a new fileopen("file.txt", "w") or "x"
ReadAccess existing datafile.read()
UpdateAdd or modify contentfile.write() or "a" mode
DeleteRemove a fileos.remove("file.txt")

This guide focuses on reading and writing text files — the most commonly used operations.


Text Files vs Binary Files — What’s the Difference?

Before we start writing code, it’s important to understand the two main types of files Python can work with.

Text Files

Text files store data as human-readable characters encoded using a character encoding standard (most commonly UTF-8).

Examples of text files:

  • .txt — plain text documents
  • .csv — comma-separated data
  • .log — application log files
  • .json — structured data format
  • .html / .py — source code files

When you open a .txt file in Notepad, you can read its contents directly. That’s because it’s stored as text.

Binary Files

Binary files store data as raw bytes — not human-readable characters. They represent images, audio, video, executable programs, and compressed archives.

Examples:

  • .jpg, .png — image files
  • .mp3, .wav — audio files
  • .exe, .pyc — compiled executables
  • .zip — compressed archives

When Python works with binary files, it reads and writes raw byte sequences without any encoding or decoding.

# Opening a text file
with open("notes.txt", "r") as f:
    content = f.read()  # Returns a string

# Opening a binary file
with open("image.jpg", "rb") as f:
    data = f.read()  # Returns raw bytes

Which One Does This Guide Cover?

This guide focuses exclusively on text files — the most beginner-friendly and commonly used file type in everyday Python programming.

🔗 For an introduction to working with binary data and more advanced file types, refer to the official Python documentation on file I/O.


How to Open a File in Python — The open() Function

The open() function is the starting point for all file operations in Python. Before you can read from or write to a file, you must open it.

Basic Syntax

file_object = open(filename, mode, encoding)
ParameterDescriptionRequired?
filenameThe name (or path) of the file✅ Yes
modeHow to open the file ('r', 'w', 'a', etc.)❌ Optional (default: 'r')
encodingCharacter encoding to use❌ Strongly recommended

Your First File Operation

Let’s start with the simplest possible example — opening a file and reading it:

# Step 1: Open the file
file = open("hello.txt", "r", encoding="utf-8")

# Step 2: Read the content
content = file.read()

# Step 3: Print it
print(content)

# Step 4: Close the file (IMPORTANT)
file.close()

The open() function returns a file object — a special Python object that provides methods for interacting with the file.

File Object Properties

Once you’ve opened a file, you can inspect its properties:

file = open("example.txt", "r", encoding="utf-8")

print("File name:", file.name)      # example.txt
print("File mode:", file.mode)      # r
print("Is closed?:", file.closed)   # False

file.close()
print("Is closed?:", file.closed)   # True

Always Specify Encoding

One of the most common beginner mistakes is forgetting to specify the file encoding.

# ❌ Can cause UnicodeDecodeError on some systems
file = open("data.txt", "r")

# ✅ Safe and portable — always recommended
file = open("data.txt", "r", encoding="utf-8")

UTF-8 is the universal standard encoding that supports nearly every character and symbol from all modern languages. Always use it unless you have a specific reason not to.

💡 Why does this matter? If your file contains special characters (accents, non-Latin scripts, symbols) and you don’t specify encoding, Python may interpret the bytes incorrectly and throw a UnicodeDecodeError.

The close() Method — And Why It Matters

After you’re done working with a file, you must close it.

file = open("notes.txt", "r", encoding="utf-8")
# ... do something with file ...
file.close()  # Release the file from memory

Failing to close a file can cause:

  • Memory leaks — the file stays locked in RAM
  • Data corruption — buffered writes may not be saved to disk
  • File lock issues — other programs can’t access the file
  • Program crashes in long-running applications

⚠️ Better approach: Instead of manually calling close(), use the with statement (covered in detail later). It handles closing automatically — even if an error occurs.


File Modes Explained — r, w, a, x, and More

The mode parameter tells Python how you want to open the file. Choosing the wrong mode is one of the most common (and costly) beginner mistakes.

Complete File Mode Reference

ModeFull NameBehaviorFile Must Exist?
'r'ReadOpens for reading only. Default mode.✅ Yes — error if missing
'w'WriteOpens for writing. Deletes all existing content. Creates if not exists.❌ No
'a'AppendOpens for writing at end of file. Creates if not exists.❌ No
'x'Exclusive CreateCreates a new file. Error if file already exists.❌ No — must NOT exist
'r+'Read + WriteOpens for both reading and writing. File must exist.✅ Yes
'w+'Write + ReadOpens for both. Overwrites existing content.❌ No
'a+'Append + ReadOpens for reading and appending.❌ No
'rb'Read BinaryReads raw bytes (for images, audio, etc.)✅ Yes
'wb'Write BinaryWrites raw bytes❌ No

Code Examples for Each Mode

# 'r' — Read mode (most common for reading)
with open("notes.txt", "r", encoding="utf-8") as f:
    print(f.read())

# 'w' — Write mode (CAUTION: erases existing content!)
with open("output.txt", "w", encoding="utf-8") as f:
    f.write("This will replace everything in the file.\n")

# 'a' — Append mode (safe for adding to existing files)
with open("log.txt", "a", encoding="utf-8") as f:
    f.write("New entry added.\n")

# 'x' — Exclusive create (safe for creating new files)
try:
    with open("newfile.txt", "x", encoding="utf-8") as f:
        f.write("Brand new file!\n")
except FileExistsError:
    print("File already exists — not overwritten.")

⚠️ The Most Dangerous Mode: 'w'

This is critical for beginners to understand:

# Suppose notes.txt contains 500 lines of important data...

# ❌ THIS DESTROYS ALL EXISTING CONTENT INSTANTLY
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Oops.")

# The 500 lines are GONE. There is no undo.

Rule: Only use 'w' mode when you intentionally want to overwrite a file from scratch. Use 'a' when you want to add to existing content.


Reading Files in Python

Python gives you four different ways to read a text file, each suited to different situations.

Method 1: read() — Read the Entire File as a String

The read() method reads the entire file content and returns it as a single string.

with open("poem.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)

Output (if poem.txt contains):

Roses are red,
Violets are blue,
Python is awesome,
And so are you!

You can also read a specific number of characters:

with open("poem.txt", "r", encoding="utf-8") as file:
    first_10 = file.read(10)  # Reads only the first 10 characters
    print(first_10)           # "Roses are"

✅ Best used when:

  • The file is small (a few KB)
  • You need the entire content as one string for processing

❌ Avoid when:

  • The file is large (MBs or GBs) — it loads everything into RAM at once

Method 2: readline() — Read One Line at a Time

The readline() method reads one single line from the file and returns it as a string, including the newline character \n at the end.

with open("poem.txt", "r", encoding="utf-8") as file:
    line1 = file.readline()   # "Roses are red,\n"
    line2 = file.readline()   # "Violets are blue,\n"
    line3 = file.readline()   # "Python is awesome,\n"

    print(line1.strip())  # .strip() removes the \n
    print(line2.strip())
    print(line3.strip())

Each call to readline() advances the file pointer to the next line. When it reaches the end of the file, it returns an empty string "".

# Reading with a while loop
with open("poem.txt", "r", encoding="utf-8") as file:
    while True:
        line = file.readline()
        if not line:   # Empty string = end of file
            break
        print(line.strip())

✅ Best used when:

  • You want to process the file one line at a time
  • You need fine-grained control over reading position

Method 3: readlines() — Read All Lines into a List

The readlines() method reads the entire file and returns a list of strings, where each item is one line (including \n).

with open("poem.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()

print(lines)
# ['Roses are red,\n', 'Violets are blue,\n', 'Python is awesome,\n', 'And so are you!']

# Loop through all lines cleanly
for line in lines:
    print(line.strip())

✅ Best used when:

  • You need all lines available as a list to index, slice, or sort
  • The file is small enough to load into memory entirely

Method 4: Iterating Over the File Object Directly (Best Practice for Large Files)

This is the most memory-efficient way to read a file, and the approach recommended by most Python professionals.

with open("large_data.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line.strip())  # Processes one line at a time

Python reads the file line by line without loading the entire file into memory. This is essential when working with large files (log files, data exports, etc.).

# Example: Count lines in a large file
line_count = 0
with open("server_log.txt", "r", encoding="utf-8") as file:
    for line in file:
        line_count += 1

print(f"Total lines: {line_count}")

Quick Comparison: Which Method to Use?

MethodReturnsMemory UsageBest For
read()Single stringHigh (entire file)Small files, full-text processing
readline()One line (string)Very lowSequential line-by-line with control
readlines()List of stringsHigh (entire file)When you need list operations on lines
for line in fileOne line per iterationVery low ✅Large files — recommended default

Writing to Files in Python

Writing to files in Python is just as simple as reading. You use the 'w' mode and the write() or writelines() method.

The write() Method — Write a String

The write() method writes a single string to the file and returns the number of characters written.

with open("greeting.txt", "w", encoding="utf-8") as file:
    file.write("Hello, World!\n")
    file.write("Welcome to Python file handling.\n")
    file.write("This is your first written file!")

Content of greeting.txt:

Hello, World!
Welcome to Python file handling.
This is your first written file!

⚠️ Important: write() does not add a newline character automatically. You must add \n yourself at the end of each line.

# ❌ This produces one long line with no line breaks
file.write("Line one")
file.write("Line two")
# Output: "Line oneLine two"

# ✅ Always add \n for line breaks
file.write("Line one\n")
file.write("Line two\n")
# Output:
# Line one
# Line two

Writing Variables and Formatted Data

In real applications, you’ll often write the value of variables — not hard-coded text.

name = "Alice"
age = 28
city = "London"

with open("user_profile.txt", "w", encoding="utf-8") as file:
    file.write(f"Name: {name}\n")
    file.write(f"Age: {age}\n")
    file.write(f"City: {city}\n")

Content of user_profile.txt:

Name: Alice
Age: 28
City: London

The writelines() Method — Write Multiple Lines at Once

The writelines() method accepts a list of strings and writes them all to the file in one call.

shopping_list = [
    "Apples\n",
    "Bread\n",
    "Milk\n",
    "Butter\n",
    "Eggs\n"
]

with open("shopping.txt", "w", encoding="utf-8") as file:
    file.writelines(shopping_list)

⚠️ Common Trap: writelines() does NOT add newlines automatically either. Each string in your list must already include \n.

# ❌ No line breaks — all items run together
items = ["Apples", "Bread", "Milk"]
file.writelines(items)
# Output: "ApplesBreadMilk"

# ✅ Add \n to each item
items = ["Apples\n", "Bread\n", "Milk\n"]
file.writelines(items)
# Output:
# Apples
# Bread
# Milk

A cleaner approach using a list comprehension:

items = ["Apples", "Bread", "Milk", "Butter"]

with open("shopping.txt", "w", encoding="utf-8") as file:
    file.writelines(item + "\n" for item in items)

Appending Data to Files

Appending is one of the most useful — and most misunderstood — file operations. It’s the safe way to add content to a file without destroying what’s already there.

'w' vs 'a' — The Critical Difference

# ❌ WRITE mode — DESTROYS existing content every time
with open("diary.txt", "w", encoding="utf-8") as file:
    file.write("Monday: Had a great day!\n")

# Running it again erases Monday's entry and only keeps this:
with open("diary.txt", "w", encoding="utf-8") as file:
    file.write("Tuesday: Went for a walk.\n")
# diary.txt now ONLY contains Tuesday's entry.


# ✅ APPEND mode — PRESERVES existing content
with open("diary.txt", "a", encoding="utf-8") as file:
    file.write("Wednesday: Cooked a new recipe.\n")
# diary.txt now contains ALL three entries.

Building a Running Log File

A classic use of append mode — writing a new timestamped entry each time your program runs:

import datetime

def log_event(message):
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_entry = f"[{timestamp}] {message}\n"

    with open("app_log.txt", "a", encoding="utf-8") as log_file:
        log_file.write(log_entry)

# Call this throughout your program
log_event("Application started")
log_event("User logged in: Alice")
log_event("File processed: data.csv")
log_event("Application closed")

Content of app_log.txt after multiple runs:

[2025-03-15 09:00:01] Application started
[2025-03-15 09:00:02] User logged in: Alice
[2025-03-15 09:00:05] File processed: data.csv
[2025-03-15 09:00:10] Application closed
[2025-03-15 14:30:00] Application started
[2025-03-15 14:30:01] User logged in: Bob

💡 Real-world connection: This exact pattern is what web servers, desktop apps, and cloud services use to write their log files every single day.


Using the with Statement — The Modern Best Practice

If there’s one single concept that will immediately level up your Python file handling code, it’s this: always use the with statement.

The Old Way (Fragile and Error-Prone)

# ❌ Old approach — manual open and close
file = open("data.txt", "r", encoding="utf-8")
content = file.read()
print(content)
file.close()  # You MUST remember this

This works fine… most of the time. But what if an error occurs between open() and close()?

file = open("data.txt", "r", encoding="utf-8")
content = file.read()
result = int(content)  # ❌ ValueError if content isn't a number!
file.close()           # This line NEVER runs — file stays open forever

If a runtime error occurs, file.close() is never reached. The file stays open, holding system resources, potentially causing data corruption or locking the file from other programs.

The Modern Way — with Statement (Context Manager)

# ✅ Modern approach — file closes automatically
with open("data.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)
# File is automatically closed here — even if an error occurred above

The with statement creates a context — a protected block of code. When execution leaves that block (either normally or due to an error), Python automatically calls file.close() for you.

Why with is Superior: A Clear Comparison

# ❌ Fragile: Manual approach
file = open("scores.txt", "r", encoding="utf-8")
data = file.read()
score = int(data.strip())   # If this fails, file never closes
file.close()

# ✅ Robust: with statement
with open("scores.txt", "r", encoding="utf-8") as file:
    data = file.read()
    score = int(data.strip())   # If this fails, file STILL closes safely

The 4 Key Benefits of with

  1. Automatic closure — no file.close() needed
  2. Exception-safe — file closes even if an error occurs inside the block
  3. Memory efficient — system resources are freed promptly
  4. Cleaner code — reduces boilerplate and is easier to read

Working with Multiple Files Simultaneously

The with statement can open multiple files at once:

# Read from one file, write to another
with open("raw_data.txt", "r", encoding="utf-8") as input_file, \
     open("processed_data.txt", "w", encoding="utf-8") as output_file:

    for line in input_file:
        processed = line.strip().upper()  # Transform each line
        output_file.write(processed + "\n")

print("Processing complete!")

🏆 Golden Rule: From this point forward, always write with open(...) — never just open(). This single habit will save you from countless hard-to-find bugs.


Handling Errors and Exceptions

Files can be unpredictable. A file might be missing, a folder might not exist, or your program might not have permission to access it. Proper error handling is what separates beginner code from production-ready code.

🔗 For a deeper understanding of Python error handling, see our Python Exception Handling Tutorial.

Common File-Related Exceptions

ExceptionWhen It Occurs
FileNotFoundErrorFile or directory does not exist
PermissionErrorInsufficient permissions to read/write
IsADirectoryErrorTried to open a directory as a file
FileExistsErrorFile already exists (raised by 'x' mode)
UnicodeDecodeErrorFile encoding mismatch
IOError / OSErrorGeneral I/O failure

Basic Error Handling with try/except

try:
    with open("missing_file.txt", "r", encoding="utf-8") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("Error: The file does not exist. Please check the filename.")

Handling Multiple Exception Types

try:
    with open("data.txt", "r", encoding="utf-8") as file:
        content = file.read()
        print(content)

except FileNotFoundError:
    print("❌ File not found. Please check the path and filename.")

except PermissionError:
    print("❌ Permission denied. You don't have access to this file.")

except UnicodeDecodeError:
    print("❌ Encoding error. Try opening with a different encoding.")

except IOError as e:
    print(f"❌ An I/O error occurred: {e}")

Using finally for Guaranteed Cleanup

The finally block runs no matter what — whether an exception occurred or not. Useful for logging or cleanup tasks:

try:
    with open("config.txt", "r", encoding="utf-8") as file:
        config = file.read()
        print("Config loaded successfully.")

except FileNotFoundError:
    print("Config file not found. Using default settings.")
    config = "DEFAULT"

finally:
    print("File operation attempt complete.")  # Always runs

Checking If a File Exists Before Opening

Sometimes you want to check for a file’s existence before attempting to open it:

import os

filename = "user_data.txt"

if os.path.exists(filename):
    with open(filename, "r", encoding="utf-8") as file:
        print(file.read())
else:
    print(f"'{filename}' not found. Creating a new one...")
    with open(filename, "w", encoding="utf-8") as file:
        file.write("New file created.\n")

Or using the modern pathlib approach:

from pathlib import Path

file_path = Path("user_data.txt")

if file_path.exists():
    content = file_path.read_text(encoding="utf-8")
    print(content)
else:
    print("File does not exist.")

A Production-Ready File Reading Pattern

Here’s the robust, complete pattern used in real applications:

def read_file_safely(filename):
    """Safely reads a text file and returns its content."""
    try:
        with open(filename, "r", encoding="utf-8") as file:
            return file.read()

    except FileNotFoundError:
        print(f"[ERROR] '{filename}' was not found.")
        return None

    except PermissionError:
        print(f"[ERROR] Permission denied for '{filename}'.")
        return None

    except Exception as e:
        print(f"[ERROR] Unexpected error reading '{filename}': {e}")
        return None

# Usage
content = read_file_safely("notes.txt")
if content:
    print(content)

Common Mistakes Beginners Make

Here are the most frequent file handling errors beginners make — and exactly how to fix them.


❌ Mistake 1: Forgetting to Close the File

# ❌ Wrong — file is never closed
file = open("notes.txt", "r", encoding="utf-8")
content = file.read()
print(content)
# file.close() is missing!

# ✅ Right — use with statement
with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()
    print(content)

❌ Mistake 2: Using 'w' Mode by Accident on Important Files

# ❌ DANGER — This silently deletes everything in the file
with open("customer_database.txt", "w", encoding="utf-8") as file:
    file.write("New entry\n")
# All previous customer records are now GONE

# ✅ Use 'a' mode to safely add data
with open("customer_database.txt", "a", encoding="utf-8") as file:
    file.write("New entry\n")

❌ Mistake 3: Forgetting \n When Writing Multiple Lines

# ❌ All text runs together on one line
with open("list.txt", "w", encoding="utf-8") as file:
    file.write("Item 1")
    file.write("Item 2")
    file.write("Item 3")
# Result: "Item 1Item 2Item 3"

# ✅ Add newline characters
with open("list.txt", "w", encoding="utf-8") as file:
    file.write("Item 1\n")
    file.write("Item 2\n")
    file.write("Item 3\n")

❌ Mistake 4: Not Specifying Encoding

# ❌ May fail with UnicodeDecodeError on non-ASCII characters
with open("international.txt", "r") as file:
    content = file.read()

# ✅ Always specify encoding
with open("international.txt", "r", encoding="utf-8") as file:
    content = file.read()

❌ Mistake 5: Loading Huge Files Entirely into Memory

# ❌ Will crash or slow down on a 2GB log file
with open("massive_log.txt", "r", encoding="utf-8") as file:
    content = file.read()  # Loads 2GB into RAM!

# ✅ Read line by line — memory efficient
with open("massive_log.txt", "r", encoding="utf-8") as file:
    for line in file:
        process(line)   # Handles one line at a time

❌ Mistake 6: Hardcoding Absolute Paths

# ❌ Only works on your computer
with open("C:\\Users\\Alice\\Documents\\data.txt", "r") as file:
    content = file.read()

# ✅ Use pathlib for portable, cross-platform paths
from pathlib import Path

file_path = Path("data") / "data.txt"  # Works on Windows, Mac, Linux
with open(file_path, "r", encoding="utf-8") as file:
    content = file.read()

❌ Mistake 7: No Error Handling at All

# ❌ Will crash with an unhandled error if file is missing
with open("config.txt", "r", encoding="utf-8") as file:
    settings = file.read()

# ✅ Always handle potential errors
try:
    with open("config.txt", "r", encoding="utf-8") as file:
        settings = file.read()
except FileNotFoundError:
    print("Config file missing — using defaults.")
    settings = "DEFAULT_SETTINGS"

Real-World Examples and Mini Projects

Let’s apply everything you’ve learned to build four small but practical programs.


🗂️ Mini Project 1: Personal To-Do List App

A simple command-line to-do list that saves tasks to a file permanently.

TODO_FILE = "todo_list.txt"

def add_task(task):
    """Append a new task to the to-do list."""
    with open(TODO_FILE, "a", encoding="utf-8") as file:
        file.write(task.strip() + "\n")
    print(f"✅ Task added: '{task}'")

def view_tasks():
    """Display all current tasks."""
    try:
        with open(TODO_FILE, "r", encoding="utf-8") as file:
            tasks = file.readlines()

        if not tasks:
            print("📋 Your to-do list is empty.")
        else:
            print("\n📋 Your To-Do List:")
            for i, task in enumerate(tasks, start=1):
                print(f"  {i}. {task.strip()}")

    except FileNotFoundError:
        print("📋 No to-do list found. Start by adding a task!")

# --- Main Program ---
add_task("Learn Python file handling")
add_task("Build a portfolio project")
add_task("Read 20 pages of a book")
view_tasks()

Output:

✅ Task added: 'Learn Python file handling'
✅ Task added: 'Build a portfolio project'
✅ Task added: 'Read 20 pages of a book'

📋 Your To-Do List:
  1. Learn Python file handling
  2. Build a portfolio project
  3. Read 20 pages of a book

📊 Mini Project 2: Word Frequency Counter

Reads a text file and counts how many times each word appears — a classic text analysis task.

def count_word_frequency(filename):
    """Count word frequency in a text file."""
    word_count = {}

    try:
        with open(filename, "r", encoding="utf-8") as file:
            for line in file:
                words = line.lower().strip().split()
                for word in words:
                    # Remove punctuation
                    clean_word = word.strip(".,!?;:'\"()")
                    if clean_word:
                        word_count[clean_word] = word_count.get(clean_word, 0) + 1

    except FileNotFoundError:
        print(f"❌ File '{filename}' not found.")
        return {}

    # Sort by frequency (most common first)
    sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
    return sorted_words

# Write a sample file to analyse
with open("sample.txt", "w", encoding="utf-8") as f:
    f.write("Python is great. Python is easy. Python is powerful.\n")
    f.write("Learning Python is fun. Python developers love Python.\n")

# Run the frequency counter
results = count_word_frequency("sample.txt")

print("📊 Word Frequency Analysis:")
for word, count in results[:10]:  # Top 10
    print(f"  '{word}': {count} times")

Output:

📊 Word Frequency Analysis:
  'python': 6 times
  'is': 5 times
  'great': 1 times
  'easy': 1 times
  'powerful': 1 times
  'learning': 1 times
  'fun': 1 times
  'developers': 1 times
  'love': 1 times

📋 Mini Project 3: Application Activity Logger

A reusable logger that writes timestamped entries to a log file — the same concept used in real software.

import datetime

LOG_FILE = "activity_log.txt"

def log(level, message):
    """Write a timestamped log entry to the log file."""
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    entry = f"[{timestamp}] [{level.upper()}] {message}\n"

    with open(LOG_FILE, "a", encoding="utf-8") as log_file:
        log_file.write(entry)

    print(entry.strip())  # Also print to console

def view_recent_logs(n=5):
    """Display the last n log entries."""
    try:
        with open(LOG_FILE, "r", encoding="utf-8") as log_file:
            lines = log_file.readlines()

        print(f"\n📋 Last {n} log entries:")
        for line in lines[-n:]:
            print(" ", line.strip())

    except FileNotFoundError:
        print("No log file found yet.")

# Simulate application activity
log("INFO",    "Application started")
log("INFO",    "User 'alice' logged in")
log("WARNING", "Disk usage above 80%")
log("INFO",    "File 'report.csv' processed successfully")
log("ERROR",   "Failed to connect to database")
log("INFO",    "Application shutting down")

view_recent_logs(n=3)

⚙️ Mini Project 4: Simple Config File Reader

Reads a plain .txt configuration file with key=value pairs and parses it into a Python dictionary — a pattern used widely in real software.

def create_default_config(filename):
    """Write a default configuration file."""
    config_content = """# App Configuration File
app_name=MyPythonApp
version=1.0.0
debug_mode=False
max_retries=3
log_file=app_log.txt
theme=dark
"""
    with open(filename, "w", encoding="utf-8") as file:
        file.write(config_content)
    print(f"✅ Default config created: '{filename}'")


def read_config(filename):
    """Parse a key=value config file into a dictionary."""
    config = {}

    try:
        with open(filename, "r", encoding="utf-8") as file:
            for line in file:
                line = line.strip()

                # Skip empty lines and comments
                if not line or line.startswith("#"):
                    continue

                # Split on first '=' only
                if "=" in line:
                    key, value = line.split("=", 1)
                    config[key.strip()] = value.strip()

    except FileNotFoundError:
        print(f"❌ Config file '{filename}' not found.")

    return config


# Create and then read the config
create_default_config("config.txt")
settings = read_config("config.txt")

print("\n⚙️  Loaded Configuration:")
for key, value in settings.items():
    print(f"  {key}: {value}")

# Access individual settings
print(f"\nApp: {settings.get('app_name')} v{settings.get('version')}")
print(f"Debug mode: {settings.get('debug_mode')}")

Output:

✅ Default config created: 'config.txt'

⚙️  Loaded Configuration:
  app_name: MyPythonApp
  version: 1.0.0
  debug_mode: False
  max_retries: 3
  log_file: app_log.txt
  theme: dark

App: MyPythonApp v1.0.0
Debug mode: False

Frequently Asked Questions (FAQs)

Q1: How do I read and write text files in Python?

Use Python’s built-in open() function. For reading: open("file.txt", "r", encoding="utf-8"). For writing: open("file.txt", "w", encoding="utf-8"). Always wrap the call in a with statement for safe, automatic file closure.


Q2: What is the difference between read(), readline(), and readlines()?

  • read() — Returns the entire file as one string. Best for small files.
  • readline() — Returns one line at a time as a string. Best for sequential processing with fine control.
  • readlines() — Returns all lines as a list of strings. Best when you need list operations on lines.

Q3: How do I append to a file without overwriting it in Python?

Use the append mode 'a':

with open("file.txt", "a", encoding="utf-8") as file:
    file.write("This is added at the end.\n")

This preserves all existing content and adds new data at the end.


Q4: What happens if I use 'w' mode on a file that already exists?

All existing content is permanently deleted and replaced with whatever you write. There is no undo. Use 'a' mode if you want to preserve existing data.


Q5: Why should I use with open() instead of just open()?

The with statement is a context manager that automatically closes the file when the block ends — even if an exception occurs. Without it, you risk memory leaks, data corruption, and locked files if your code crashes before reaching file.close().


Q6: How do I handle a FileNotFoundError in Python?

Use a try/except block:

try:
    with open("missing.txt", "r", encoding="utf-8") as file:
        content = file.read()
except FileNotFoundError:
    print("File not found!")

Q7: What encoding should I use when opening text files in Python?

Always use encoding="utf-8". UTF-8 is the universal standard that supports characters from virtually all languages and prevents UnicodeDecodeError.


Q8: Can Python create a new file if it doesn’t exist?

Yes. Modes 'w', 'a', and 'x' will all create a new file if it doesn’t exist. The difference:

  • 'w' — creates and overwrites if it already exists
  • 'a' — creates and preserves if it already exists
  • 'x' — creates only; raises an error if it already exists

Q9: How do I read a specific line from a file in Python?

with open("file.txt", "r", encoding="utf-8") as file:
    lines = file.readlines()
    third_line = lines[2]  # Lines are 0-indexed
    print(third_line.strip())

Q10: What is the best way to read a large file in Python?

Iterate over the file object directly — it reads one line at a time without loading the entire file into memory:

with open("large_file.txt", "r", encoding="utf-8") as file:
    for line in file:
        process(line)

Conclusion

You’ve now covered everything you need to confidently read and write text files in Python like a professional developer.

Here’s a quick recap of the key concepts:

ConceptKey Takeaway
open()Gateway to all file operations — always specify encoding="utf-8"
File modes'r' = read, 'w' = write (overwrites!), 'a' = append, 'x' = create new
read() / readline() / readlines()Three ways to read — choose based on file size and use case
write() / writelines()Write strings — always add \n manually
with statementAlways use this — automatic, safe file closure
Error handlingWrap in try/except — handle FileNotFoundError, PermissionError, etc.
Large filesIterate with for line in file — never load large files with read()
EncodingAlways encoding="utf-8" — prevents UnicodeDecodeError

Your Next Steps

Now that you’ve mastered Python file handling, here’s what to explore next:

Build Something Real

The best way to cement what you’ve learned is to build something. Try one of these mini projects:

  1. A personal journal app that saves daily entries to a dated .txt file
  2. A grade tracker that reads student scores from a file and calculates averages
  3. A word counter tool that analyses the complexity of any text document
  4. A file backup utility that copies important files to a backup folder

File handling is the bridge between your Python programs and the real world. Master it, and you’ll have the foundation for working with data, building tools, and writing production-quality code.

💬 What are you going to build with Python file handling? Drop your ideas or questions in the comments below!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *