File::Raw · File::Raw::Separated 0.04
File::Raw::Separated
CSV and TSV, parsed in C, as a File::Raw plugin.
A CSV or TSV file to rows in one call: arrays, or hashes keyed by the header. RFC 4180 by default, every dialect knob when the file needs one, and a stream for files larger than memory.
Registers csvtsv
use File::Raw ();
use File::Raw::Separated;
my $rows = File::Raw::slurp('people.csv', plugin => 'csv', header => 1);
print "$_->{name} is $_->{age}\n" for @$rows;
my $tabs = File::Raw::slurp('people.tsv', plugin => 'tsv');
What you get
-
csv and tsv
Two plugins, the same options: RFC 4180 quoting by default,
sep,quote,escape,trimandeolwhen a file differs. -
Arrays or hashes
Rows as arrays, or
header => 1for hashes keyed by the first line. -
Lenient, or strict
By default a malformed row is recovered.
strict => 1croaks with the byte offset instead, and the path when streaming. -
Larger than memory
file_parse_streamreads a file a row at a time, and hands the callback the same array each row so nothing is allocated per line. -
In chains
After
gziporbase64in apluginchain, a compressed or encoded file is rows in one call.
In use
use File::Raw::Separated qw(import);
# Files larger than memory: one row at a time.
my $total = 0;
file_parse_stream('people.csv', sub {
my $row = $_[0]; # reused between calls: copy it to keep it
$total += $row->[1] if $row->[1] =~ /^\d+$/;
});
print "$total\n";
The numbers
Against the fastest alternative that was installed, and shown whichever way it went.
- 3.4x read a 6.8 MB CSV file into rows, against Text::CSV_XS File::Raw::Separated 0.04 at 23.2/s, Text::CSV_XS 1.62 at 6.8/s
- 2.7x read a 6.8 MB CSV file into hashes by its header, against Text::CSV_XS File::Raw::Separated 0.04 at 6.8/s, Text::CSV_XS 1.62 at 2.5/s
Measured on Apple M5, darwin with perl 5.42.0, 2026-10-19: each entry timed for 3 CPU seconds by the Benchmark module, 3 times, the median kept, after checking that both sides produced the same result. Every number.
Works with
Chains from its documentation: the plugins run left to right on a read, right to left on a write.
plugin => ['gzip', 'csv']with File::Raw::Gzipplugin => ['base64', 'csv']with File::Raw::Base64