Python File Handling: Open, Read, Write and Delete Files - Python with AI tutorial chapter 30
Python

Python File Handling: Open, Read, Write and Delete Files

Python with AI Tutorial · Chapter 30 of 48

Python file handling means creating, reading, writing, appending and deleting files from your scripts. The built-in open() function and the with statement do the reading and writing, while pathlib handles paths, folders and file operations in a way that works identically on Windows, Mac and Linux.

Almost every automation touches a file: a log to append to, a text export to clean up, a folder of reports to rename. The habits in this chapter, always using with, always passing an encoding and building paths with pathlib, prevent the three most common file bugs before they happen.

Writing a text file

Open a file in "w" mode to create it (or overwrite it if it exists), then call write or writelines. The with block closes the file automatically, even if an error occurs halfway through.

with open("sales_notes.txt", "w", encoding="utf-8") as f:
    f.write("Q1 review: North region up 12%\n")
    f.write("Q2 review: South region flat\n")
    f.writelines(["Action: call Acme Ltd\n", "Action: renew Zen Foods contract\n"])

print("Saved")
Output:
Saved

Note that write does not add a newline for you; include \n yourself. Without encoding="utf-8", Windows falls back to a legacy code page and characters such as the rupee sign or accented names can be corrupted.

Reading a text file

There are three common ways to read: read() returns everything as one string, readlines() returns a list, and looping over the file object gives one line at a time without loading the whole file into memory. The loop is the right choice for anything large.

with open("sales_notes.txt", encoding="utf-8") as f:
    content = f.read()

print(content, end="")
print(len(content.splitlines()), "lines")

with open("sales_notes.txt", encoding="utf-8") as f:
    for number, line in enumerate(f, start=1):
        if line.startswith("Action"):
            print(number, line.strip())
Output:
Q1 review: North region up 12%
Q2 review: South region flat
Action: call Acme Ltd
Action: renew Zen Foods contract
4 lines
3 Action: call Acme Ltd
4 Action: renew Zen Foods contract
Mode Meaning If the file exists If it does not
"r" Read (default) Opens for reading FileNotFoundError
"w" Write Erases the content Creates it
"a" Append Adds to the end Creates it
"x" Exclusive create FileExistsError Creates it
"r+" Read and write Opens, keeps content FileNotFoundError
"b" suffix Binary (e.g. "rb", "wb") Bytes instead of text; no encoding argument
"t" suffix Text (default) Strings with newline translation

Appending to a log file

"a" mode is what you want for logs and audit trails: existing lines stay, new lines go at the end, and the file is created on the first run.

from datetime import datetime

with open("app.log", "a", encoding="utf-8") as log:
    log.write(f"{datetime(2026, 9, 5, 9, 15).isoformat()} report generated\n")
    log.write(f"{datetime(2026, 9, 5, 9, 16).isoformat()} email sent\n")

with open("app.log", encoding="utf-8") as log:
    print(log.read(), end="")
Output (first run):
2026-09-05T09:15:00 report generated
2026-09-05T09:16:00 email sent
Common mistake: calling open() without with and forgetting close(). The data may sit in a buffer and never reach the disk, and on Windows the file stays locked so Excel cannot open it. If you ever must open a file manually, wrap the work in try / finally and close it there.

Paths with pathlib: Windows versus Mac and Linux

Windows separates folders with backslashes (C:\Users\priya\reports) while Mac and Linux use forward slashes (/Users/priya/reports). pathlib.Path hides that difference: build paths with the / operator and Python writes the correct separator for the machine it runs on.

from pathlib import Path

base = Path("reports") / "2026" / "september"
base.mkdir(parents=True, exist_ok=True)

summary = base / "summary.txt"
summary.write_text("Total invoices: 42\n", encoding="utf-8")

print(summary)
print(summary.exists(), summary.suffix, summary.stem)
print(summary.read_text(encoding="utf-8").strip())
print(Path.home())
Output on Windows:
reports\2026\september\summary.txt
True .txt summary
Total invoices: 42
C:\Users\priya

Output on Mac / Linux:
reports/2026/september/summary.txt
True .txt summary
Total invoices: 42
/Users/priya

If you must type a Windows path by hand, use a raw string (r"C:\Users\priya\reports") or forward slashes ("C:/Users/priya/reports"); both are accepted. A plain string with backslashes breaks on sequences such as \n or \t.

Listing files in a folder

glob finds files matching a pattern in one folder and rglob searches sub-folders too. Each result is a Path with a name, suffix, size and modified time, which is all you need to build clean-up or archive scripts.

from pathlib import Path

for p in sorted(Path("reports").rglob("*.txt")):
    print(p.name, "-", p.stat().st_size, "bytes")

txt_files = list(Path(".").glob("*.txt"))
print(len(txt_files), "text file(s) in the current folder")
Output:
summary.txt - 19 bytes
1 text file(s) in the current folder

Handling missing files and permissions

Files disappear, get renamed or are locked by another program. Check with Path.exists() when you only need a yes or no, and catch FileNotFoundError and PermissionError around the open call when you want the script to carry on gracefully.

from pathlib import Path

def read_config(path):
    try:
        with open(path, encoding="utf-8") as f:
            return f.read()
    except FileNotFoundError:
        print(f"Missing: {path} - using defaults")
        return ""
    except PermissionError:
        print(f"No permission to read {path}")
        return ""

print(repr(read_config("does_not_exist.ini")))
print(Path("sales_notes.txt").exists(), Path("does_not_exist.ini").exists())
Output:
Missing: does_not_exist.ini - using defaults
''
True False

Copying, renaming and deleting

shutil.copy copies a file, Path.rename moves or renames it, Path.unlink deletes a file and shutil.rmtree removes a whole folder tree. Deletion is permanent, so check the path twice and prefer missing_ok=True over a bare call that raises when the file is already gone.

import shutil
from pathlib import Path

src = Path("sales_notes.txt")
backup = Path("sales_notes_backup.txt")

shutil.copy(src, backup)
archived = backup.rename("sales_notes_2026.txt")
print(archived.exists(), backup.exists())

archived.unlink()
Path("never_existed.txt").unlink(missing_ok=True)
print(archived.exists())

shutil.rmtree("reports")
print(Path("reports").exists())
Output:
True False
False
False

Binary files

Images, PDFs, Excel workbooks and zip archives are binary. Open them with a "b" mode and you get bytes instead of strings; there is no encoding because there is no text. Reading the first few bytes is a reliable way to detect a file type regardless of its extension.

from pathlib import Path

Path("sample.bin").write_bytes(bytes([0x50, 0x4B, 0x03, 0x04]))

with open("sample.bin", "rb") as f:
    head = f.read(4)

print(head, len(head))
print("Looks like a zip or xlsx:", head.startswith(b"PK"))
Output:
b'PK\x03\x04' 4
Looks like a zip or xlsx: True
Try it with AI

Ask for a safe archive script and read the explanation before running it.

Write a Python script using pathlib and shutil that looks in C:\Reports (or ~/Reports on Mac) for .pdf files older than 90 days, moves them into an Archive/YYYY-MM sub-folder based on each file's modified date, creates folders as needed, never overwrites an existing file, and prints a summary of what it moved. Add a dry_run=True flag that only prints the plan.
Try it with AI

Get a log parser for a real file you have.

I have a text log where each line looks like "2026-09-05 09:15:22 ERROR Payment gateway timeout order=1042". Write Python that reads the file line by line with a with block, counts lines per level (INFO, WARNING, ERROR), collects the order numbers mentioned in ERROR lines, and writes the ERROR lines to errors_only.txt. Handle a missing file with a friendly message.

Common mistakes

  • Opening in "w" mode to add a line, which wipes the existing content. Use "a" to append.
  • Omitting encoding="utf-8", so files written on one machine read as garbage on another.
  • Building paths with string concatenation and a hard-coded slash. Use Path(a) / b.
  • Reading a large file with read() when a line-by-line loop would use almost no memory.
  • Deleting with unlink() or rmtree() before checking the path is really the one you meant.

Exercise

Write a function word_count(path) that returns how many lines, words and characters a text file contains, reading it line by line. Test it on sales_notes.txt from the first example.

Show answer
def word_count(path):
    lines = words = chars = 0
    with open(path, encoding="utf-8") as f:
        for line in f:
            lines += 1
            words += len(line.split())
            chars += len(line)
    return lines, words, chars

print(word_count("sales_notes.txt"))   # (4, 20, 115)

Related chapters

FAQ

Why should I use with open() instead of open() and close()?

The with statement closes the file automatically, even when an exception occurs, so buffered data is flushed to disk and the file is not left locked.

What is the difference between w and a mode in Python?

w truncates the file to empty before writing, so old content is lost. a keeps the existing content and writes new data at the end. Both create the file if it is missing.

How do I write file paths that work on both Windows and Mac?

Use pathlib.Path and join parts with the / operator, for example Path(“reports”) / “2026” / “summary.txt”. Python inserts the correct separator for each operating system.

Working with spreadsheets too? Ready-made Excel, Google Sheets and Power BI templates are at NextGenTemplates.com.

Chapter 30 of 48 · Python with AI: all 48 chapters

PK
Meet PK, the founder of NeotechNavigators.com! With over 15 years of experience in Data Visualization, Excel Automation, and dashboard creation. PK is a Microsoft Certified Professional who has a passion for all things in Excel. PK loves to explore new and innovative ways to use Excel and is always eager to share his knowledge with others. With an eye for detail and a commitment to excellence, PK has become a go-to expert in the world of Excel. Whether you're looking to create stunning visualizations or streamline your workflow with automation, PK has the skills and expertise to help you succeed. Join the many satisfied clients who have benefited from PK's services and see how he can take your data analysis skills to the next level!
https://neotechnavigators.com