CSV.jl
CSV.jl reads and writes comma-separated and other delimited text data. Its readers and writer implement the Tables.jl interfaces, so CSV data can move between Julia table packages without a CSV-specific adapter.
Installation
Install the registered release in the Julia REPL:
] add CSVCSV.jl 1.0 requires Julia 1.10 or later. Read Migrating to 1.0 before you update an application from CSV.jl 0.10.
First read and write
using CSV
input = IOBuffer("name,score\nAda,9.5\nGrace,10.0\n")
file = CSV.File(input)
(names(file), String.(file.name), collect(file.score))([:name, :score], ["Ada", "Grace"], [9.5, 10.0])CSV.File is a Tables.jl table. A table sink can consume it directly. The writer accepts any Tables.jl table:
output = IOBuffer()
CSV.write(output, (name=["Ada", "Grace"], score=[9.5, 10.0]))
String(take!(output))"name,score\nAda,9.5\nGrace,10.0\n"Select a reader
| API | Use it when | Materialization model |
|---|---|---|
CSV.File | You need a normal in-memory table | Index once, then parse columns |
CSV.read | You want to hand the parsed columns to a sink | Same parse as CSV.File; marks columns as safe to take |
CSV.lazy | You need a fast first look or sparse cell access | Index now; parse each accessed cell later |
CSV.Rows | You process rows once and do not need columns | Indexes the source; materializes cells on access |
CSV.Chunks | You process a large table in bounded batches | Indexes once; parses one stable-schema batch at a time |
CSV.lazy, CSV.Rows, and CSV.Chunks do not stream an unbounded input. They retain the source bytes and a structural index. See Input and memory behavior for the exact source rules.
Data model
CSV.jl builds one quote-aware structural index. It then parses each selected column with a type-specialized loop. Parallel execution does not change row order, limit results, or output bytes.
Date-time columns prefer Timestamp{Nanosecond} from Durations.jl, which uses Dates.Timestamp when the standard library provides it. Wider dates use microseconds if all values fit exactly; otherwise the column stays text. Request Dates.DateTime with types when a consumer needs it.
Text columns use DataStrings.DataString by default. Short values are stored in the value; longer values live in buffers the column owns, so an eager table never refers to its source. Convert with String(value) when a standalone String is required, or pass stringtype=String to a reader.
Parse problems are structured data. A read prints one summary warning and keeps the problems; call CSV.problems(file) to inspect them, set on_error=:collect to skip the warning, or on_error=:error when a parse problem must stop the read with a CSV.ParseError.
- Reading data
- Writing data
- Examples
- Start here: read, inspect, and write
- Non-UTF-8 character encodings
- Concatenate multiple inputs at once
- Gzipped input
- Delimited data in a string
- Data from the web/a url
- Reading from a zip file
- Column names on 2nd row
- No column names in data
- Manually provide column names
- Multi-row column names
- Normalizing column names
- Skip to specific row where data starts
- Skipping trailing useless rows
- Reading transposed data
- Ignoring commented rows
- Ignoring empty rows
- Including/excluding columns
- Limiting number of rows from data
- Specifying custom missing strings
- String delimiter
- Fixed width files
- Turning off quoted cell parsing
- Quoted & escaped fields
- DateFormat
- Custom decimal separator
- Thousands separator
- Custom groupmarks
- Custom bool strings
- Matrix-like Data
- Providing types
- Typemap
- Pooled values
- Non-string pooled values
- Pool with absolute threshold
- Exact decimal columns
- Inspect bad values
- Rows that do not match the header
- Keep empty text distinct from missing
- Write to an in-memory buffer
- Read into another table package
- Process rows or batches
- Index first and parse later
- API reference
- CSV.jl 1.0 release notes
- Migrating from 0.10 to 1.0