File I/O and Formats
Get bytes in and out without losing anything
Reading and writing CSV, JSON, Parquet and Avro correctly — encodings, chunking, compression and atomic writes — is where pipelines most often lose data or speed.
What you will learn
- Read/write CSV, JSON and Parquet with the right encodings and types
- Use chunked reads for large files
- Write atomically (temp file + rename) and handle compression
What is this?
Every pipeline begins and ends with files. The formats — CSV, JSON, Parquet, Avro — differ in compression, schema fidelity and cost. Correct I/O means: right encoding, right types, atomic writes, and streaming reads when the file outgrows memory.
Why do you need it?
- A CSV with a trailing comma or BOM silently mis-parses until data is wrong.
- Parquet stores typed, compressed, columnar data — the de-facto lake format — while JSON re-parses text every read.
- Atomic writes (temp + rename) mean readers never see half-written files.
Mental model
Shipping containers vs loose mail
Parquet/columnar vs CSV/text
Loose envelopes (CSV) arrive in any order, easily crumpled, re-read by a human every time. Containers (Parquet) are packed, labeled with a manifest (schema), and unloaded efficiently by machines.
How it works
- CSV: Row-oriented text; read with `csv` module / pandas, minding delimiter, quotes, encoding and header row.
- JSON: nested but text; `json.loads` per line for NDJSON; schema not enforced.
- Parquet: columnar binary with embedded schema + compression (snappy/zstd); fast column subset reads.
- Avro: row-oriented binary with an explicit schema — great for Kafka's Schema Registry model.
- Chunking (`read_csv(chunksize=...)`) streams rows so RAM bounds, not file size, defines feasibility.
Choosing a format by use case.
Examples
Atomic, compressed CSV write
import os, tempfiledef atomic_write(df, path): with tempfile.NamedTemporaryFile("w", suffix=".csv", delete=False) as tmp: df.to_csv(tmp.name, index=False) os.replace(tmp.name, path) # readers see only the complete fileWrites land in a temp path and are renamed into place, so a crash mid-write never leaves a partial file at the target.
In production
- A nightly export writes `orders_YYYYMMDD.parquet` with snappy to S3, then the catalog registers the new partition.
- A webhook consumer logs each payload as a line of NDJSON for later replay and debug.
- An extractor streams a 30 GB CSV in chunks into a DuckDB/warehouse instead of reading it whole.
Best practices
- Prefer Parquet over CSV/JSON for any analytics data — schema, compression and columnar reads.
- Always specify encoding='utf-8' for both read and write; be explicit, never default.
- Write atomically for anything a reader could observe mid-write.
- Chunk or stream reads for files approaching memory; cap buffers explicitly.
Common mistakes
- Opening files in binary/text interchangeably and breaking parsing or encodings.
- Writing directly to the final path, risking torn files readers interpret as valid-but-empty.
- Storing analytics data as JSON because it is 'flexible', then paying schema-less pain at query time.
- Forgetting that gzip on CSV defeats columnar skipping — Parquet beats compress('csv.gz') for analytics.
Common issues
UnicodeDecodeError on a 'text' fileThe file is actually latin-1/UTF-16 or contains binary sequences
Detect encoding (charset-normalizer) or open with encoding='utf-8', errors='replace' and log warns.
Readers see partially-written filesWriting in place without atomic replacement
Write to a temp file then os.replace; or write to `.part` and rename on success.
Debugging tips
- When a load 'shifts' columns, re-read the raw file and inspect the first 3 lines with a hexdump or repr.
- Check byte size after writing — a 0-byte 'success' almost always means opened the wrong path.
- Diff row counts between source and target per partition to spot dropped/bad rows.
Interview checkpoint
Hands-on lab
- Convert a small CSV into typed, compressed Parquet
- Prove atomic write behavior with a partial-write simulation
- Re-read Parquet and verify types and row counts survived
Round-Trip a Dataset Across Formats Safely
30 min · intermediate
Quick quiz
A 40 GB CSV must feed analytics. Which path is best?
A success marker rename guarantees readers never observe a half-written dataset.