[Python Series 6] Read and Write Data With Files and JSON

한국어 버전

If Part 5 was about splitting logic into functions and modules, Part 6 is about moving data safely in and out of your scripts. Real-world automation often reads a file, transforms it, then persists the result elsewhere. Python's standard library alone can cover text, CSV, and JSON workflows. We'll lean on pathlib and json to manage paths in an OS-agnostic way and to serialize data without hassle.

Key terms

  1. pathlib.Path: A standard-library class that treats paths as objects instead of raw strings.
  2. Serialization: Turning in-memory data into a string or file so it can be stored or transmitted.
  3. JSON Lines: A log-friendly format where each line is its own JSON object, typically saved with .jsonl.

Core ideas

Study memo

  • Time: 60 minutes
  • Prereqs: Function/module based project, comfort with basic types and control flow
  • Goal: Read and write files using pathlib and json, with clear error handling patterns

Delegate path handling to Path objects and serialization to JSON. Your automation scripts will depend less on the host OS and stay easier to reason about.

Code examples

Manage paths with pathlib

Path objects abstract away platform-specific separators, so the same code works on macOS, Windows, or Linux.

from pathlib import Path

data_dir = Path("data")

log_file = data_dir / "logs.txt"
print(log_file)

Path.mkdir(exist_ok=True) creates the folder if it does not exist and stays quiet if it already does.

Read and write text files

log_file.write_text("Deployment finished\n", encoding="utf-8")

content = log_file.read_text(encoding="utf-8")
print(content)

Use the open() context manager when you need finer control over modes or iteration.

with log_file.open("a", encoding="utf-8") as fp:
    fp.write("Monitoring started\n")

with log_file.open("r", encoding="utf-8") as fp:
    for line in fp:
        print(line.strip())

Work with JSON

JSON powers APIs, configuration files, and logs alike.


config = {
    "slack_webhook": "https://hooks.slack.com/...",
    "channels": ["deploy", "alert"],
}

config_file = data_dir / "config.json"

config_file.write_text(json.dumps(config, ensure_ascii=False, indent=2), encoding="utf-8")

loaded = json.loads(config_file.read_text(encoding="utf-8"))
print(loaded["channels"])

ensure_ascii=False preserves non-ASCII characters, so Korean or emoji stay intact.

Handle exceptions deliberately

File operations fail when a path is missing or permissions change. Catch those scenarios early.

try:
    report_text = (data_dir / "report.txt").read_text(encoding="utf-8")
except FileNotFoundError:
    report_text = "The report file has not been generated yet."

print(report_text)

That pattern keeps the script running and surfaces a friendly message instead of a crash.

Mini project: JSON-backed TODO store

from pathlib import Path

db_file = Path("data/todos.json")

def load_todos() -> list[dict]:
    if not db_file.exists():
        return []
    return json.loads(db_file.read_text(encoding="utf-8"))

def save_todos(todos: list[dict]) -> None:
    db_file.write_text(json.dumps(todos, ensure_ascii=False, indent=2), encoding="utf-8")

def add_todo(title: str):
    todos = load_todos()
    todos.append({"title": title, "done": False})
    save_todos(todos)

add_todo("Draft the report outline")
print(load_todos())

This template shows the essential loop of read → mutate → write using files and JSON.

User inputCLI / automationtodo_app.pyadd_todo / load_todospathlib.PathPath/folder managementdata/todos.jsonJSON fileNext scriptReads and reuses Add todoCreate directorieswrite_text / json.dumpsread_text / json.loads

Thinking in terms of Path + JSON clarifies which functions manage directories and which handle serialization.

In practice: Deployment logs as JSON Lines

Log each API deployment as JSON Lines (.jsonl) so systems like OpenSearch or ClickHouse can ingest them immediately.

📄 What is JSON Lines? Each line stores exactly one JSON object. Streaming systems and log shippers can ingest it line by line without parsing entire files.

from datetime import datetime
from pathlib import Path

log_file = Path("data/deploy.jsonl")

def write_entry(level: str, message: str, **context):
    entry = {
        "timestamp": datetime.utcnow().isoformat(),
        "level": level,
        "message": message,
        **context,
    }
    with log_file.open("a", encoding="utf-8") as fp:
        fp.write(json.dumps(entry, ensure_ascii=False) + "\n")

write_entry("INFO", "Deployment finished", service="attendance", version="1.4.2")

This pattern scales from school automations to data pipelines, and we will reuse it for API logging in the next chapter.

Why it matters

School reports, club attendance sheets, and automation scripts all sit on top of file IO. Safe path handling prevents accidental deletions in the wrong directory, and JSON serialization keeps the data portable across tools and languages.

Practice

  • Follow along: Create a data directory, run the JSON TODO store, and confirm that files appear.
  • Extend: Use the JSON Lines logger to split logs per level, or switch ensure_ascii off/on to see how Unicode behaves.
  • Debug: Intentionally read from a missing path to raise FileNotFoundError, then recover with Path.mkdir(exist_ok=True) or a try/except block.
  • Done when: You can read and write both text and JSON while managing paths through helper functions you can reuse.

Wrap up

Mastering file and JSON IO dramatically widens what your automation scripts can do. Next up, we'll call external APIs with requests and combine those responses with the file patterns you built here.

💬 댓글

이 글에 대한 의견을 남겨주세요