15  Files

15.1 The Wall

AI wrote code that saved data to a file. You ran it, saw “Data saved!”, and felt good. Then you restarted the program and the data was gone. It turned out AI opened the file with "w" (write mode) instead of "a" (append mode), so every run erased the previous data.

In another case, AI read a file but forgot to handle the case where the file did not exist. The program crashed with FileNotFoundError, on the user’s machine, not yours, because the file was in your test folder.

This chapter fixes that.

15.2 Thinking Session

15.2.1 Getting Oriented

NoteThinking Session Prompt

How does file I/O work in Python? Explain the open/read/write/close pattern. What are the different file modes (r, w, a, x) and when would I use each? Why does AI-generated code always use with open() instead of calling open() and close() separately?

Your AI should explain that with open() is a context manager that automatically closes the file even if an error occurs. The modes matter: "r" reads, "w" writes (erases existing content), "a" appends, "x" creates (fails if file exists). AI should always use with, if it does not, that is a code smell.

15.2.2 Go Deeper

NoteThinking Session Prompt

What is the difference between reading a file with read(), readline(), and readlines()? And for writing, what is the difference between write() and writelines()? When does AI use each one?

TipWhat to Look For

read() returns the entire file as one string. readline() returns one line. readlines() returns a list of lines. For writing, write() takes a string, writelines() takes a list of strings (and does not add newlines). AI usually uses read() for small files and iterates line by line for large ones.

NoteThinking Session Prompt

How do I work with JSON files in Python? AI-generated code often saves configuration and data as JSON. Show me how to read and write JSON files using the json module.

15.2.3 Challenge It

NoteThinking Session Prompt

What is wrong with this code?

f = open("data.txt", "w")
f.write("Hello")
# program crashes here
f.close()
TipWhat to Look For

If the program crashes between open() and close(), the file is never properly closed, potentially losing data. The fix is with open("data.txt", "w") as f:. The with block guarantees closure. Also, "w" mode erases existing content, if that is not intended, use "a".

15.2.4 What You Should Have Learned

  • Always use with open(). It handles closing automatically
  • File modes: "r" read, "w" write (erases), "a" append
  • read() gets all content, iterate for line-by-line processing
  • JSON is the standard format for structured data: json.load() / json.dump()
  • Always handle FileNotFoundError when reading files

15.3 The Gap

Files give your chatbot memory that survives between runs. Without files, everything resets when the program stops. Now you know how to read, write, and append, and how to use JSON for structured data. You also know the most common file bug AI generates: wrong file mode.

In the Building Session, you will give your chatbot persistent memory.

15.4 Building Session

15.4.1 The Spec

Add file persistence to your chatbot:

  • Save conversation history to a JSON file after each session
  • Load previous conversation history when the chatbot starts
  • Handle the case where the history file does not exist yet
  • Add a “save” command to save mid-conversation

15.4.2 Prompt It

NoteBuilding Session Prompt

Update my chatbot to v1.5. Add file-based persistence:

  • Save conversation history to “chat_history.json” using json.dump()
  • Load previous history on startup using json.load() with FileNotFoundError handling
  • The history should be a list of dicts: [{“role”: “user”, “text”: “…”}, {“role”: “bot”, “text”: “…”}]
  • Add a “save” command that saves the current history
  • Auto-save when the user quits
  • Add import json at the top

Keep existing dictionary-based response system from v1.4.

15.4.3 Read the Code

Your AI will produce something like this:

import json

HISTORY_FILE = "chat_history.json"


def load_history():
    """Load conversation history from file."""
    try:
        with open(HISTORY_FILE, "r") as f:
            return json.load(f)
    except FileNotFoundError:
        return []


def save_history(history):
    """Save conversation history to file."""
    with open(HISTORY_FILE, "w") as f:
        json.dump(history, f, indent=2)
TipWhat to Notice

json.load() reads structured data from a file. json.dump() writes it. indent=2 makes the JSON human-readable. The try/except FileNotFoundError handles the first run when no history file exists yet. "w" mode is correct here because we write the entire history each time (not appending).

15.4.4 Stretch It

NoteBuilding Session Prompt

Add a “history” command that loads and displays the last 10 entries from the saved file, formatted with timestamps. Use the datetime module to add timestamps when saving each entry.

15.5 Your Chatbot So Far

  • Ch 1-14: Full features with dictionaries, loops, string processing
  • Ch 15: Persistent conversation history saved to JSON file

15.6 Quick Reference

# Read a file
with open("file.txt", "r") as f:
    content = f.read()        # entire file
    lines = f.readlines()     # list of lines

# Write a file
with open("file.txt", "w") as f:    # erases first
    f.write("hello\n")

# Append to a file
with open("file.txt", "a") as f:    # keeps existing
    f.write("more\n")

# JSON
import json
with open("data.json", "r") as f:
    data = json.load(f)
with open("data.json", "w") as f:
    json.dump(data, f, indent=2)

# Handle missing file
try:
    with open("file.txt") as f:
        data = f.read()
except FileNotFoundError:
    data = ""