Table of Contents
Why Build File-Based Programs?
By now you know how to open, read, and write files. In this chapter, you’ll use those skills to create small, practical programs that:
- Remember information between runs (using a file as storage)
- Read data from one file and write results to another
- Process text to extract or transform information
You’ll see complete mini-programs that are still simple enough for beginners to read and modify.
General Pattern for File-Based Programs
Most simple file-based programs follow this pattern:
- Get input
- From the user (
input()) - From a file (using
open()and.read()/.readline()/ looping) - Process the data
- Do calculations, filtering, counting, or formatting
- Save or display the result
- Print to the screen
- Write to a file with
write()orwritelines()
You can think of it like a factory:
$$
\text{File(s) + User Input} \;\rightarrow\; \text{Your Code} \;\rightarrow\; \text{Output File(s) + Screen Output}
$$
Example 1: A Simple Note Saver
This program lets the user type a note, and then saves it to a text file. Each note is added on a new line.
# simple_note_saver.py
filename = "notes.txt"
note = input("Type your note: ")
# Add the note to the file, keeping old notes
with open(filename, "a", encoding="utf-8") as file:
file.write(note + "\n")
print("Note saved to", filename)Key ideas specific to this style of program:
- Use append mode
"a"when you want to keep existing data and add more. - Add
"\n"yourself if you want each note on its own line. - Only the file name is hard-coded; everything else comes from the user.
Try extending it:
- Ask for a title and the note, and save both.
- Add the current date/time to each note (using the
datetimemodule, covered later).
Example 2: Viewing Saved Notes
Now add a second program to read and show the notes you saved.
# view_notes.py
filename = "notes.txt"
try:
with open(filename, "r", encoding="utf-8") as file:
contents = file.read()
if contents.strip() == "":
print("No notes found.")
else:
print("Your notes:")
print(contents)
except FileNotFoundError:
print("No notes file found yet. Add a note first.")New pattern here:
- Wrap
open()intry/exceptto handle missing files without crashing. - Use
.strip()to check if a file is effectively empty (only whitespace/newlines).
Example 3: A Very Simple Log Counter
Imagine you have a file log.txt where every line is some kind of event:
# Example log.txt
login
view_page
logout
login
view_page
view_page
logoutYou can write a program that counts how many times each event appears.
# count_events.py
filename = "log.txt"
counts = {}
with open(filename, "r", encoding="utf-8") as file:
for line in file:
event = line.strip()
if event == "":
continue # skip empty lines
if event in counts:
counts[event] += 1
else:
counts[event] = 1
print("Event counts:")
for event, count in counts.items():
print(event, "=>", count)What’s specific to this style of program:
- It reads line by line and processes each line.
- It uses a dictionary to accumulate results.
- It ignores empty lines, which is common when processing text files.
You can adapt this pattern to:
- Count how many times each word appears in a text file.
- Count how many lines contain a certain word.
Example 4: Copying and Transforming a File
This program reads one file and writes a modified version to a new file. For example, you can convert all text to uppercase.
# shout_copy.py
source = "input.txt"
target = "output_shout.txt"
with open(source, "r", encoding="utf-8") as in_file, \
open(target, "w", encoding="utf-8") as out_file:
for line in in_file:
upper_line = line.upper()
out_file.write(upper_line)
print("Created", target)Specific techniques here:
- Open two files at the same time using a single
withstatement. - Transform each line before writing it out.
- This pattern is common for text processing: read → change → write.
You could change:
line.upper()toline.lower()- or strip spaces:
line.strip() - or replace text:
line.replace("old", "new")
Example 5: Simple To-Do List (File-Based)
This example combines input, output, and file storage into one simple program.
It will:
- Load tasks from a file (if it exists)
- Show a menu to the user
- Let the user:
- Add a task
- View tasks
- Save and quit
# todo_list.py
FILENAME = "tasks.txt"
def load_tasks():
tasks = []
try:
with open(FILENAME, "r", encoding="utf-8") as file:
for line in file:
task = line.strip()
if task:
tasks.append(task)
except FileNotFoundError:
# No file yet, start with empty list
pass
return tasks
def save_tasks(tasks):
with open(FILENAME, "w", encoding="utf-8") as file:
for task in tasks:
file.write(task + "\n")
def show_tasks(tasks):
if not tasks:
print("No tasks yet.")
else:
print("Your tasks:")
for i, task in enumerate(tasks, start=1):
print(f"{i}. {task}")
def main():
tasks = load_tasks()
while True:
print("\nMenu:")
print("1. View tasks")
print("2. Add task")
print("3. Save and quit")
choice = input("Choose an option (1-3): ")
if choice == "1":
show_tasks(tasks)
elif choice == "2":
new_task = input("Enter a new task: ")
if new_task.strip():
tasks.append(new_task.strip())
print("Task added.")
else:
print("Empty task not added.")
elif choice == "3":
save_tasks(tasks)
print("Tasks saved. Goodbye!")
break
else:
print("Invalid choice. Please try again.")
if __name__ == "__main__":
main()What’s important about this example:
- The file acts as a simple database of tasks.
- Data is loaded once at the start and saved once at the end.
- Tasks are stored one per line, a very common format for simple programs.
- The program is interactive but still uses files for long-term storage.
Ideas to extend:
- Allow deleting tasks.
- Mark tasks as done and save this information.
- Save both task text and priority by separating them with a character (for example,
task|high).
Example 6: Searching in a File
This program asks the user for a word and then shows all lines from a file that contain that word.
# search_in_file.py
filename = "data.txt"
word = input("Enter a word to search for: ").strip()
if not word:
print("You did not enter a word.")
else:
try:
with open(filename, "r", encoding="utf-8") as file:
found_any = False
for line_number, line in enumerate(file, start=1):
if word in line:
print(f"Line {line_number}: {line.rstrip()}")
found_any = True
if not found_any:
print("No matches found.")
except FileNotFoundError:
print("File", filename, "not found.")This shows a very common file-based pattern:
- Get search criteria from the user.
- Go through a file line by line, checking for matches.
- Show matching lines with line numbers.
Combining Ideas: Design Tips for Simple File Programs
When designing your own file-based programs:
- Decide what the file represents
- One item per line (tasks, notes, events)
- One line with many values
- Multiple files for different categories
- Choose how data is updated
- Append new data (
"a") - Rewrite the whole file (
"w") after changes - Read-result → modify in memory → save once at the end
- Handle missing files gracefully
- Use
try/except FileNotFoundError - Start from an empty list or empty string if no file exists
- Keep the format simple
- Start with “one thing per line”
- Use simple separators like
|or,only when needed - Separate logic into functions
- One function to load data from the file
- One function to save data
- Other functions to process the data
Practice Ideas
Here are small projects you can try to practice building file-based programs:
- A daily journal that:
- Adds a date and time to each entry
- Lets you view all entries
- A score tracker for a game:
- Ask for player name and score
- Save them to a file
- Another program reads the file and shows the top scores
- A contact list:
- Save each contact’s name and email on one line
- Let the user add contacts and list all contacts
In each case, think about:
- What does one line represent?
- How will the program load, modify, and save that data?
These simple patterns are the foundation for more advanced programs that work with larger data files, configuration files, or even simple databases.