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
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
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?
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.
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
What is wrong with this code?
f = open("data.txt", "w")
f.write("Hello")
# program crashes here
f.close()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
FileNotFoundErrorwhen 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
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)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
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 = ""