CSV


Overview

Eta ships a native CSV subsystem backed by vincentlaucsb/csv-parser. The public API is in std.csv, with optional bridge helpers in std.fact_table.

Key properties:


Quick Start

(import std.csv)

;; Reader
(define r (csv:open-reader "trades.csv"))
(define cols (csv:columns r))
(define rec  (csv:read-record r))
(csv:close r)

;; Writer
(define w (csv:open-writer "out.csv" :column-names '(symbol qty price)))
(csv:write-record w '((symbol . "AAPL") (qty . 100) (price . 150.25))
                  '(symbol qty price))
(csv:close w)

std.csv API

Reader:

Streaming helpers:

Writer:


Options

Accepted keyword options (symbols or strings, with or without leading :):

KeyReaderWriterDefault
delimiteryesyes#\,
quoteyesyes#\"
headeryesyes#t
header-rowyesno0
trimyesno#t
commentyesno#f
column-namesyesyes#f
null-tokensyesno("" "NA" "NaN")
quote-policynoyes'minimal
infer-types?fact-table-load onlyno#t

Writer quote-policy values:


Typed Rows

csv:read-typed-row parses each cell as:

  1. nil if it matches a null token.
  2. Fixnum if integer parse succeeds (from_chars).
  3. Flonum if floating parse succeeds (from_chars).
  4. String otherwise.

This parsing is locale-independent. Example: 1,5 stays a string unless the CSV delimiter is set so the cell text itself is a valid numeric form.


FactTable Bridge

std.fact_table provides:

Examples:

(import std.fact_table)

(define ft (fact-table-load-csv "trades.csv" :infer-types? #t))
(fact-table-save-csv ft "trades-out.csv")

fact-table-load-csv supports the reader options plus :infer-types?. When :infer-types? #f, numeric-looking cells are kept as strings.


Threading Note

CSV reader and writer handles are stateful heap objects and are not safe for concurrent mutation from multiple Eta threads.