How to split a CSV into multiple files in Python

Splitting by line count (split -l) breaks CSVs whose quoted fields contain line breaks and drops the header from every part but the first. This script splits by records, every N rows or by a column's value, and repeats the header.

1. The script

Save as split_csv.py:

import csv, re, sys
from pathlib import Path

def split_rows(src, size, out):
    with open(src, newline='', encoding='utf-8-sig') as f:
        reader = csv.reader(f)
        header = next(reader)
        rows = [r for r in reader if any(c.strip() for c in r)]
    width = len(str((len(rows) + size - 1) // size))
    for i in range(0, len(rows), size):
        write(out / f'part-{i // size + 1:0{width}}.csv', header, rows[i:i + size])

def split_by(src, column, out):
    groups = {}
    with open(src, newline='', encoding='utf-8-sig') as f:
        reader = csv.DictReader(f)
        header = reader.fieldnames
        for r in reader:
            if any((v or '').strip() for v in r.values()):
                groups.setdefault((r[column] or '').strip(), []).append([r[h] for h in header])
    used = set()
    for value, rows in groups.items():
        base = re.sub(r'[\\/:*?"<>|\x00-\x1f]+', '_', value).strip('. ')[:60] or 'blank'
        name, n = base, 2
        while name.lower() in used:
            name, n = f'{base}_{n}', n + 1
        used.add(name.lower())
        write(out / f'{name}.csv', header, rows)

def write(path, header, rows):
    with open(path, 'w', newline='', encoding='utf-8') as f:
        w = csv.writer(f)
        w.writerow(header)
        w.writerows(rows)

src, how, out = sys.argv[1], sys.argv[2], Path(sys.argv[3] if len(sys.argv) > 3 else 'parts')
out.mkdir(exist_ok=True)
split_rows(src, int(how), out) if how.isdigit() else split_by(src, how, out)
print(f'{len(list(out.glob("*.csv")))} files in {out}/')

2. Run it

python3 split_csv.py big.csv 1000          # part-1.csv, part-2.csv, ... 1000 rows each
python3 split_csv.py big.csv Region        # one file per value of the Region column
python3 split_csv.py big.csv Region out    # write into ./out instead of ./parts

On the country-codes file (249 rows) 50 gave 5 files of 50/50/50/50/49 rows, Continent gave 7 files (AF, AN, AS, EU, NA, OC, SA) and "Region Name" gave 6, including blank.csv for the one row without a region (Antarctica).

3. What it does

4. Limits

5. No code

The free split CSV tool does the same in your browser, every N rows or by column, and downloads all parts as one .zip. Nothing is uploaded.

Frequently asked questions

How do I split a CSV on the command line?

tail -n +2 big.csv | split -l 1000 - part_ splits the rows; then add the header to each part: for f in part_*; do (head -n 1 big.csv; cat "$f") > "$f.csv"; rm "$f"; done. It counts lines, so quoted fields containing line breaks can be split in two.

How do I split a CSV with pandas?

for value, part in df.groupby('Region'): part.to_csv(f'{value}.csv', index=False) splits by column, but read the file with dtype=str and keep_default_na=False so codes like NA and 02134 survive, and rows with an empty Region are dropped by groupby unless you pass dropna=False.

Can I merge the parts back?

Yes: the free merge CSV files tool on this site combines them into one file and matches columns by name.

Written with AI assistance. The script was run on 2026-10-01 with Python 3 standard library only, on the open country-codes dataset (datasets/country-codes on GitHub: 249 rows, 56 columns) split every 50 rows, by Continent and by Region Name, and on an edge-case file (quoted line breaks, blank values, file names that collide after cleaning). Every output file was compared cell for cell with the free split CSV tool on this site: 0 mismatches. PlainTables is our extension; the other methods are free and built into Excel, Google Sheets and pandas.