Skip to main content

Writer

Struct Writer 

Source
pub struct Writer<W: Write> { /* private fields */ }
Expand description

Writes CSV data to a Write sink.

Fields containing the delimiter, a newline, or a double-quote are automatically quoted. "" escape sequences are used for quotes within quoted fields. Empty fields are written unquoted (as nothing), which is what every mainstream CSV writer does.

Internal buffering is used to avoid many small writes. Callers should not wrap the writer in a BufWriter.

§Security

This writer does not defend against CSV / formula injection (CWE-1236). Quoting a field does not neutralise it: spreadsheet applications still evaluate a quoted cell whose first character is =, +, -, @, tab or carriage return. If the data being written is attacker-controlled and the output is opened in a spreadsheet, sanitise those leading characters yourself (for example by prefixing an apostrophe) or disable formula evaluation in the consuming application.

§Example

use csv::Writer;

let mut w = Writer::new(Vec::new());
w.write_row(["name", "age", "city"])?;
w.write_row(["Alice", "30", "New York, NY"])?;
let result = String::from_utf8(w.into_inner()?).unwrap();
assert_eq!(result, "name,age,city\r\nAlice,30,\"New York, NY\"\r\n");

Implementations§

Source§

impl<W: Write> Writer<W>

Source

pub fn new(writer: W) -> Self

Create a new writer wrapping the given output sink.

The writer starts with default comma delimiter and strict field-count validation (all rows must have the same number of fields).

Source

pub fn set_delimiter(self, byte: u8) -> Self

Set the field delimiter byte (default is ,).

§Panics

Panics if byte is ", \r or \n; see Reader::set_delimiter.

use csv::Writer;
let mut w = Writer::new(Vec::new()).set_delimiter(b'\t');
w.write_row(["a", "b", "c"])?;
Source

pub fn set_flexible(self, yes: bool) -> Self

Set whether variable field counts are allowed (default is false).

When false (strict), all rows must have the same number of fields. When true, rows may vary in field count.

Source

pub fn set_write_bom(self, yes: bool) -> Self

Emits a UTF-8 byte-order mark (U+FEFF, the bytes EF BB BF) before any other output (default is false).

Enable this when the consumer expects one — Excel writes UTF-8 CSV with a BOM, and some tools refuse to detect the encoding without it. The mark is written once, before the first row, header or serialized record, and Reader strips a leading BOM by default, so output round-trips.

Source

pub fn set_headers(self, headers: Vec<String>) -> Self

Store column names for schema awareness.

This sets the expected header names for future serde support and strict field-count validation. It does not write anything to the output. Use write_headers to emit the header row.

Source

pub fn headers(&self) -> Option<&[String]>

Returns the stored header names, if any.

Source

pub fn write_headers<I, T>(&mut self, headers: I) -> Result<(), WriteError>
where I: IntoIterator<Item = T>, T: AsRef<str>,

Write a header row to the output and store the column names internally.

The header row is written as a single CSV line. The field count from this row becomes the expected count for all subsequent rows (unless flexible mode is enabled).

If this method has already been called, subsequent calls return WriteError::HeadersAlreadyWritten.

§Errors

Returns WriteError::HeadersAlreadyWritten if headers have already been written. Returns WriteError::InconsistentFieldCount if the number of headers differs from a prior write_row or from headers stored via set_headers. The count is validated before anything is written, so a rejected call leaves the output untouched. Returns WriteError::Io if the underlying writer fails.

Source

pub fn write_row<I, T>(&mut self, row: I) -> Result<(), WriteError>
where I: IntoIterator<Item = T>, T: AsRef<[u8]>,

Write a single row.

Each element in the iterator is written as a CSV field. Fields are auto-quoted if they contain the delimiter, a newline (\n or \r), or a double-quote ("). Empty fields are written unquoted.

§Round-tripping

A row consisting of a single empty field is written as a blank line, which readers (this one included, like most CSV readers) treat as an empty line and skip. Such a row therefore cannot be read back. Every other row round-trips exactly.

§Errors

Returns WriteError::InconsistentFieldCount if the number of fields differs from previous rows (unless flexible mode is enabled). Returns WriteError::Io if the underlying writer fails.

Source

pub fn flush(&mut self) -> Result<(), WriteError>

Flush the internal buffer to the underlying writer.

Source

pub fn into_inner(self) -> Result<W, WriteError>

Flush any remaining data and return the underlying writer.

Source§

impl<W: Write> Writer<W>

Source

pub fn serialize<T: Serialize>(&mut self, record: &T) -> Result<(), WriteError>

Serialize a record and write it as a CSV data row.

Headers must have been set (via set_headers or write_headers) before calling this method.

For structs, fields are matched by name against the stored headers and written in header column order. For sequences and tuples, elements are written positionally (the field count must equal the header count).

§Errors

Returns WriteError::Serialize if headers have not been set, or if a serde serialization error occurs (e.g. an unknown field name, or an unsupported type like a map or enum).

Returns WriteError::InconsistentFieldCount if the stored header count differs from a field count established by an earlier write_row or write_headers call (unless flexible mode is enabled). Struct fields that have no matching header are written as empty columns rather than erroring.

Returns WriteError::Io if the underlying writer fails on flush.

§Example
use csv::Writer;
use serde::Serialize;

#[derive(Serialize)]
struct Person {
    name: String,
    age: u32,
}

let mut w = Writer::new(Vec::new())
    .set_headers(vec!["name".into(), "age".into()]);

let alice = Person { name: "Alice".into(), age: 30 };
w.serialize(&alice)?;
let result = String::from_utf8(w.into_inner()?).unwrap();
assert_eq!(result, "Alice,30\r\n");

Trait Implementations§

Source§

impl<W: Write> Drop for Writer<W>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<W> Freeze for Writer<W>
where Option<W>: Freeze,

§

impl<W> RefUnwindSafe for Writer<W>

§

impl<W> Send for Writer<W>
where Option<W>: Send,

§

impl<W> Sync for Writer<W>
where Option<W>: Sync,

§

impl<W> Unpin for Writer<W>
where Option<W>: Unpin,

§

impl<W> UnsafeUnpin for Writer<W>
where Option<W>: UnsafeUnpin,

§

impl<W> UnwindSafe for Writer<W>
where Option<W>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.