pub struct Reader<R: Read> { /* private fields */ }Expand description
A pull-based CSV reader that parses records from any Read source.
The reader supports both in-memory slices (&[u8]) and streaming I/O sources
(std::io::Read) via the custom Read trait. Rows are parsed on-demand
by calling rows or rows_bytes.
§Configuration
Use builder methods for a fluent setup:
set_delimiter— change the field separator (default,)set_flexible— allow variable-length rows (defaultfalse)set_headers— supply column names without parsingset_max_record_bytes,set_max_field_bytesandset_max_columns— opt-in resource limits
§Headers
Call parse_headers to treat the first row as column
names. After doing so, headers returns a Some slice and
serde deserialization (with the serde feature) can match by field name.
§Errors
Parsing errors (unterminated quotes, trailing content after a quoted field, inconsistent field counts) are stored on the returned row and surfaced when the row’s fields are accessed. I/O errors are also stored on the row. This allows iteration to continue past malformed rows: when a record is malformed, the reader skips to the next record boundary before parsing the following record.
Errors are reported against the line on which the offending record started.
§Resource limits
By default the reader imposes no size limits, so a single enormous record
can consume an unbounded amount of memory. Applications that parse
untrusted input should set set_max_record_bytes
(and optionally set_max_field_bytes /
set_max_columns); exceeding a limit produces an
error on the row instead of exhausting memory.
§Iteration
Produces owned Row or BytesRow values. A Row validates UTF-8
on field access; BytesRow does not. Rows can outlive the reader.
§Examples
use csv::Reader;
let data = b"name,age\nAlice,30\nBob,25\n";
let mut reader = Reader::new(&data[..]);
// Parse the first row as headers.
let headers = reader.parse_headers().unwrap();
assert_eq!(headers, &["name", "age"]);
// Iterate over data rows.
for row in reader.rows() {
for field in row.iter() {
let _: &str = field.unwrap();
}
}let file = std::fs::File::open("data.csv").unwrap();
let mut reader = Reader::new(file).set_delimiter(b';');
for row in reader.rows() {
let name = row.get(0).unwrap().unwrap();
println!("{name}");
}Implementations§
Source§impl<R: Read> Reader<R>
impl<R: Read> Reader<R>
Sourcepub fn new(source: R) -> Self
pub fn new(source: R) -> Self
Creates a new Reader from any Read source.
This works with &[u8], std::io::Cursor, std::fs::File, etc.
Sourcepub fn set_delimiter(self, byte: u8) -> Self
pub fn set_delimiter(self, byte: u8) -> Self
Sets the field delimiter byte (default is ,).
§Panics
Panics if byte is ", \r or \n. These bytes carry structural
meaning in CSV and cannot be used as a delimiter: " would disable
quoting, and \r/\n would make record boundaries unrepresentable,
causing the whole input to be read as a single record.
Sourcepub fn set_flexible(self, yes: bool) -> Self
pub fn set_flexible(self, yes: bool) -> Self
Sets whether variable field counts are allowed (default is false).
Sourcepub fn set_strip_bom(self, yes: bool) -> Self
pub fn set_strip_bom(self, yes: bool) -> Self
Controls whether a UTF-8 byte-order mark (U+FEFF, the bytes
EF BB BF) at the very start of the input is skipped (default is
true).
This is what makes files produced by Excel, which writes UTF-8 CSV with
a BOM by default, work with parse_headers and
serde: without it the first header would be "\u{feff}name" and would
match no struct field.
Only the first three bytes of the stream are considered, and only once. A BOM anywhere else in the input is always treated as data.
Pass false to keep the mark as part of the first field.
Sourcepub fn set_max_record_bytes(self, max: usize) -> Self
pub fn set_max_record_bytes(self, max: usize) -> Self
Rejects any record longer than max bytes.
This is the main defence against a single crafted record exhausting
memory. When a record exceeds the limit the row carries a
ReadErrorKind::RecordTooLarge error and reading stops, because the
remainder of the oversized record cannot be skipped safely.
By default no limit is applied.
Sourcepub fn set_max_field_bytes(self, max: usize) -> Self
pub fn set_max_field_bytes(self, max: usize) -> Self
Rejects any field longer than max bytes.
When a field exceeds the limit the row carries a
ReadErrorKind::FieldTooLarge error and reading stops, because the
remainder of the oversized record cannot be skipped without reading it.
By default no limit is applied.
Sourcepub fn set_max_columns(self, max: usize) -> Self
pub fn set_max_columns(self, max: usize) -> Self
Rejects any record with more than max columns.
Each column costs at least one byte of input, so this is a cheap way to
bound the bookkeeping memory used by a record made of millions of empty
fields. When a record exceeds the limit the row carries a
ReadErrorKind::TooManyColumns error and reading stops, because
the remainder of the oversized record cannot be skipped without reading
it.
By default no limit is applied.
Sourcepub fn set_headers(self, headers: Vec<String>) -> Self
pub fn set_headers(self, headers: Vec<String>) -> Self
Sets the column names for header-based serde deserialization.
Calling this marks headers as parsed so reader.headers() returns Some,
and pins the expected field count to the number of names supplied (unless
set_flexible is enabled), exactly like
parse_headers.
Sourcepub fn headers(&self) -> Option<&[String]>
pub fn headers(&self) -> Option<&[String]>
Returns Some(&[String]) if headers were parsed or set, None otherwise.
Sourcepub fn parse_headers(&mut self) -> Result<&[String], ReadError>
pub fn parse_headers(&mut self) -> Result<&[String], ReadError>
Parses the first row as column headers and stores them internally.
Returns the header strings as a slice, and pins the expected field count
to the number of headers (unless set_flexible is
enabled).
If the input is empty this returns an empty slice and leaves
headers as None, since no header row was seen.
Sourcepub fn rows(&mut self) -> Rows<'_, R> ⓘ
pub fn rows(&mut self) -> Rows<'_, R> ⓘ
Returns an iterator over Row values (validated as UTF-8).
Sourcepub fn rows_bytes(&mut self) -> BytesRows<'_, R> ⓘ
pub fn rows_bytes(&mut self) -> BytesRows<'_, R> ⓘ
Returns an iterator over BytesRow values (no UTF-8 validation).