0Pricing
AI Agents · Lesson

Reading and Writing Files in Agent Context

open(), pathlib.Path, reading CSV/JSON/TXT files from agent tools.

Reading and Writing Files in Agent Context is a free AI Agents lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Agents learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why File I/O Matters for Agents

Agents frequently need to read configuration, store intermediate results, and write output reports. Python provides two primary ways to work with files: the built-in open() function and the modern pathlib module. Both are essential to know.

Every file operation should use a context manager (with statement) to ensure the file is closed even if an error occurs.

with open('config.txt', 'w', encoding='utf-8') as f:
    f.write('model=gpt-4o-mini\nmax_steps=20\n')

with open('config.txt', 'r', encoding='utf-8') as f:
    content = f.read()

from pathlib import Path
content = Path('config.txt').read_text(encoding='utf-8')

print(content)

Reading Files with open()

The open() function takes a filename and a mode. For reading text, use mode 'r'. You can read the entire file at once with .read(), line by line with .readline(), or all lines into a list with .readlines().

Always specify encoding='utf-8' to avoid platform-specific encoding surprises.

with open('report.txt', 'w', encoding='utf-8') as f:
    f.write('Quarterly agent report body text.')
with open('large_log.txt', 'w', encoding='utf-8') as f:
    f.write('INFO: started\nERROR: timeout\nINFO: done\n')
with open('tasks.txt', 'w', encoding='utf-8') as f:
    f.write('task one\ntask two\n')

with open('report.txt', 'r', encoding='utf-8') as f:
    full_text = f.read()
    print(f'Read {len(full_text)} characters')

with open('large_log.txt', 'r', encoding='utf-8') as f:
    for line in f:
        line = line.rstrip('\n')
        if 'ERROR' in line:
            print('Found error:', line)

with open('tasks.txt', 'r', encoding='utf-8') as f:
    tasks = f.readlines()
    tasks = [t.strip() for t in tasks]
print('Tasks:', tasks)

Writing Files with open()

Use mode 'w' to write (creates or overwrites), 'a' to append, and 'x' to create exclusively (fails if file exists). Mode 'w' truncates the file first — be careful with existing data.

# Write a new file (or overwrite)
results = ['Task 1 complete', 'Task 2 complete', 'Task 3 failed']

with open('results.txt', 'w', encoding='utf-8') as f:
    for result in results:
        f.write(result + '\n')

# Append to existing file (add without overwriting)
with open('agent_log.txt', 'a', encoding='utf-8') as f:
    f.write('2026-05-29 14:30: Agent completed batch\n')

# Create exclusively — error if file already exists
try:
    with open('unique_report.txt', 'x', encoding='utf-8') as f:
        f.write('This file is new')
except FileExistsError:
    print('File already exists, skipping')

# --- demo ---
print('results.txt contents:')
with open('results.txt', encoding='utf-8') as f:
    print(f.read())

# Try the exclusive create again now that the file exists
try:
    with open('unique_report.txt', 'x', encoding='utf-8') as f:
        f.write('This file is new')
except FileExistsError:
    print('File already exists, skipping')

pathlib.Path — Modern File Operations

pathlib.Path provides an object-oriented approach to file paths. It's more readable than os.path and handles cross-platform path separators automatically. For simple read/write operations, read_text() and write_text() are the cleanest approach.

from pathlib import Path

base = Path('agent_workspace')
base.mkdir(exist_ok=True)
config_file = base / 'config.json'
config_file.write_text('{"model": "gpt-4o-mini"}', encoding='utf-8')

if config_file.exists():
    content = config_file.read_text(encoding='utf-8')
    print('Config:', content)

output = base / 'output' / 'report.txt'
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text('Agent report\nLine 2', encoding='utf-8')

Path('image.png').write_bytes(b'\x89PNG\r\n\x1a\n' + bytes(range(100)))
binary_data = Path('image.png').read_bytes()
print(f'File size: {len(binary_data)} bytes')

Reading and Writing JSON Files

Agents frequently exchange structured data as JSON files. Use json.load() to parse a JSON file and json.dump() to write one. Always use indent=2 for human-readable output and ensure_ascii=False to preserve Unicode characters.

import json
from pathlib import Path

config_path = Path('agent_config.json')
config_path.write_text(json.dumps({'max_retries': 5, 'model': 'gpt-4o-mini'}), encoding='utf-8')

with open(config_path, 'r', encoding='utf-8') as f:
    config = json.load(f)

print('Max retries:', config.get('max_retries', 3))
print('Model:', config.get('model', 'gpt-4o-mini'))

results = {
    'run_id': 'run-001',
    'status': 'completed',
    'items_processed': 142,
    'errors': []
}

with open('results.json', 'w', encoding='utf-8') as f:
    json.dump(results, f, indent=2, ensure_ascii=False)

print('Results written to results.json')

Context Managers — The Right Way

The with statement (context manager) guarantees the file is closed when the block exits — even if an exception occurs mid-read. Without it, files can stay open and leak file descriptors, causing crashes on systems with file handle limits.

with open('data.txt', 'w', encoding='utf-8') as f:
    f.write('sample content')

f = open('data.txt', 'r')
try:
    content = f.read()
finally:
    f.close()

with open('data.txt', 'r', encoding='utf-8') as f:
    content = f.read()

with open('input.txt', 'w', encoding='utf-8') as f:
    f.write('hello\nworld\n')

with open('input.txt', 'r') as infile, \
     open('output.txt', 'w') as outfile:
    for line in infile:
        processed = line.upper()
        outfile.write(processed)

print('Done:', content)

Working with Binary Files

Use mode 'rb' to read binary files (images, PDFs, audio) and 'wb' to write them. Never try to decode binary content as text — use read_bytes()/write_bytes() with pathlib or binary modes with open().

from pathlib import Path
import base64

image_path = Path('screenshot.png')
image_path.write_bytes(b'\x89PNG\r\n\x1a\n' + bytes(range(50)))

image_bytes = image_path.read_bytes()
print(f'Image size: {len(image_bytes)} bytes')

image_b64 = base64.b64encode(image_bytes).decode('utf-8')
print(f'Base64 length: {len(image_b64)}')

response_bytes = b'...binary content from API...'
output_path = Path('output') / 'generated_image.png'
output_path.parent.mkdir(exist_ok=True)
output_path.write_bytes(response_bytes)
print('Wrote', output_path)

Handling Encoding and Newline Issues

Different systems use different newline characters (\n on Linux/macOS, \r\n on Windows). Always specify encoding='utf-8' and let Python handle newlines with newline=None (the default). For files with a BOM (byte order mark), use encoding='utf-8-sig'.

with open('data.txt', 'w', encoding='utf-8') as f:
    f.write('hello world')
with open('windows_export.csv', 'wb') as f:
    f.write('name,email\n'.encode('utf-8'))
with open('unknown_encoding.txt', 'wb') as f:
    f.write('cafe resume'.encode('latin-1'))

with open('data.txt', 'r', encoding='utf-8') as f:
    text = f.read()

with open('windows_export.csv', 'r', encoding='utf-8-sig') as f:
    content = f.read()

try:
    with open('unknown_encoding.txt', 'r', encoding='utf-8') as f:
        text = f.read()
except UnicodeDecodeError:
    with open('unknown_encoding.txt', 'r',
               encoding='utf-8', errors='replace') as f:
        text = f.read()
    print('Warning: file had encoding errors (replaced with ?)')

print('All reads completed. csv content:', repr(content))

Efficient Line-by-Line Processing

For large files (log files, datasets), avoid loading everything into memory with .read(). Iterate directly over the file object — Python reads one line at a time, keeping memory usage constant regardless of file size.

from pathlib import Path

def process_large_log(log_path):
    error_count = 0
    processed = 0

    with open(log_path, 'r', encoding='utf-8') as f:
        for line in f:  # reads one line at a time
            line = line.strip()
            if not line:
                continue

            processed += 1
            if '[ERROR]' in line:
                error_count += 1
                # Process error immediately without storing all lines
                handle_error(line)

    print(f'Processed {processed} lines, {error_count} errors')

def handle_error(line):
    print(f'Error found: {line[:80]}')

# --- demo ---
with open('demo_agent.log', 'w', encoding='utf-8') as f:
    f.write('[INFO] agent started\n')
    f.write('[ERROR] timeout calling tool search_web\n')
    f.write('[INFO] retrying\n')
    f.write('[ERROR] tool search_web failed again\n')

process_large_log('demo_agent.log')

Creating and Managing Directories

Before writing files, ensure the parent directory exists. Use Path.mkdir(parents=True, exist_ok=True) to create nested directories without errors if they already exist. This is a common setup step at the start of any agent that produces output files.

from pathlib import Path
import datetime

# Create output directory structure
today = datetime.date.today().isoformat()  # '2026-05-29'
output_dir = Path('agent_output') / today / 'reports'
output_dir.mkdir(parents=True, exist_ok=True)

print(f'Output directory: {output_dir}')

# Now write files safely
for i in range(3):
    report_path = output_dir / f'report_{i:02d}.json'
    report_path.write_text(
        '{"status": "ok"}',
        encoding='utf-8'
    )

# List all created files
for f in output_dir.iterdir():
    print(f'  {f.name}: {f.stat().st_size} bytes')

File Path Best Practices for Agents

Agents should use absolute paths or paths relative to a well-defined base directory. Never rely on the current working directory (./) because agents are often launched from different locations. Use Path(__file__).parent to get the script's directory as a base.

from pathlib import Path

# Get absolute path relative to THIS script's location
SCRIPT_DIR = Path(__file__).parent
DATA_DIR = SCRIPT_DIR / 'data'
OUTPUT_DIR = SCRIPT_DIR / 'output'

# Always resolve to absolute path before use
config = DATA_DIR / 'config.json'
print('Config path:', config.resolve())

# Check if file exists before reading
if config.exists():
    import json
    with open(config, 'r', encoding='utf-8') as f:
        settings = json.load(f)
else:
    print(f'Config not found at {config.resolve()}')
    settings = {}

# Safe output path
result_path = (OUTPUT_DIR / 'result.json').resolve()
print('Will write to:', result_path)

Quick Check: Context Managers

Test your understanding of file I/O best practices.

File I/O Recap

You now have a solid foundation for file operations in agent code:

  • Use open('file', 'r', encoding='utf-8') to read, 'w' to write, 'a' to append
  • Always use the with statement to ensure files are closed
  • pathlib.Path provides clean, cross-platform path handling with read_text()/write_text()
  • Use json.load(f) / json.dump(data, f, indent=2) for structured data
  • Iterate over files line-by-line for large files to minimize memory use
  • Use Path(__file__).parent as your base directory — never rely on cwd

Frequently asked questions

Is the “Reading and Writing Files in Agent Context” lesson free?

Yes — the full text of “Reading and Writing Files in Agent Context” is free to read here on the web, and the AI Agents course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Agents course, upgrade to CoddyKit PRO.

What will I learn in “Reading and Writing Files in Agent Context”?

open(), pathlib.Path, reading CSV/JSON/TXT files from agent tools. You practise AI Agents with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start AI Agents?

No prior experience is required. AI Agents on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Reading and Writing Files in Agent Context” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this AI Agents lesson?

Yes. Every AI Agents lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Reading and Writing Files in Agent Context
  2. Directory Traversal and File Discovery
  3. File Format Handling: CSV, JSON, and TXT
  4. Safe File Operations with Error Handling
← Back to AI Agents