Skip to content
PHP2Shell: The PHP Bug
Akshay Thakare

Reading and Writing JSON, CSV and Parquet in Python

Which file format to use where, how to read each one without surprises, and why Parquet is the default for analytics.

PythonBeginner2 min readUpdated 11 Oct 2026

Three formats, three jobs

FormatShapeSchemaBest for
CSVRows of textNone — everything is a stringExchange with spreadsheets and legacy systems
JSON / JSONLNested documentsImplicit, per recordAPIs, logs, raw landing zones
ParquetColumnar, compressedEmbedded and typedAnalytics, data lakes, warehouses

CSV: always state the types

Python.py
import csv
from decimal import Decimal
 
with open("orders.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        amount = Decimal(row["amount"])   # never float for money
        qty = int(row["qty"])

CSV has no types, no standard for nulls and many quoting dialects. Always parse explicitly and decide what an empty string means.

JSON Lines: one record per line

Python.py
import json
 
with open("events.jsonl") as f:
    for line in f:                       # streams: memory stays flat
        event = json.loads(line)

JSONL appends and streams well, so it suits raw landing zones. A single large JSON array must be loaded whole.

Parquet: columns, compression, types

Python.py
import pyarrow.parquet as pq
 
table = pq.read_table("sales.parquet", columns=["store_id", "net_sales"])  # reads 2 columns only

Parquet stores each column together. A query that needs 2 of 40 columns reads about 5% of the bytes, and min/max statistics let engines skip whole row groups.

Common mistakes

  • Using float for money. Use Decimal or integer cents.
  • Opening CSVs without newline="", which mangles embedded line breaks.
  • Writing thousands of tiny Parquet files. Aim for roughly 128 MB–1 GB per file.

Finished this note?

Share