Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Write CSV ​

This page explains how to write CSV output with rix/csv.

The examples use the public Rix facade:

cpp
#include <rix.hpp>

and access CSV through:

cpp
rix.csv

Writing turns a table of rows and fields into CSV text.

Use it when your application needs to export small datasets, reports, generated data, test fixtures, or simple tabular output.

Basic example ​

Create a file:

bash
mkdir -p ~/rix-csv-write
cd ~/rix-csv-write
touch write.cpp

Add:

cpp
#include <rix.hpp>

int main()
{
  rixlib::csv::Table table;

  table.push_back({"name", "language"});
  table.push_back({"Ada", "C++"});
  table.push_back({"Gaspard", "Vix"});

  const auto output = rix.csv.write(table);

  rix.debug.print(output);

  return 0;
}

Run it:

bash
vix run write.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run write.cpp

Expected output ​

The output should look like this:

csv
name,language
Ada,C++
Gaspard,Vix

The first row is the header.

The following rows are data rows.

Create a table ​

A CSV table is a list of rows.

A row is a list of fields.

cpp
rixlib::csv::Table table;

Add rows with push_back:

cpp
table.push_back({"name", "language"});
table.push_back({"Ada", "C++"});
table.push_back({"Gaspard", "Vix"});

Then write it:

cpp
const auto output = rix.csv.write(table);

Write a header ​

CSV does not force a special header type.

The first row can be used as a header by convention:

cpp
rixlib::csv::Table table;

table.push_back({"name", "project"});
table.push_back({"Ada", "Rix"});
table.push_back({"Gaspard", "Vix.cpp"});

const auto output = rix.csv.write(table);

Output shape:

csv
name,project
Ada,Rix
Gaspard,Vix.cpp

Write without a header ​

If your data does not need a header, start directly with data rows:

cpp
rixlib::csv::Table table;

table.push_back({"Ada", "C++"});
table.push_back({"Gaspard", "Vix"});

const auto output = rix.csv.write(table);

Output shape:

csv
Ada,C++
Gaspard,Vix

Write fields with commas ​

CSV fields that contain commas must be escaped.

Use the writer instead of building CSV manually.

cpp
rixlib::csv::Table table;

table.push_back({"name", "note"});
table.push_back({"Ada", "created with C++"});
table.push_back({"Grace", "systems, tools, and documents"});

const auto output = rix.csv.write(table);

rix.debug.print(output);

Expected shape:

csv
name,note
Ada,created with C++
Grace,"systems, tools, and documents"

The comma inside the field remains part of the field value.

Write fields with quotes ​

Quotes inside fields must be escaped.

cpp
rixlib::csv::Table table;

table.push_back({"name", "quote"});
table.push_back({"Ada", "She said \"hello\""});

const auto output = rix.csv.write(table);

rix.debug.print(output);

Expected shape:

csv
name,quote
Ada,"She said ""hello"""

Use the writer so quote escaping stays correct.

Write fields with newlines ​

Fields can contain newlines.

When a field contains a newline, the writer should quote it:

cpp
rixlib::csv::Table table;

table.push_back({"name", "note"});
table.push_back({"Ada", "line one\nline two"});

const auto output = rix.csv.write(table);

rix.debug.print(output);

Expected shape:

csv
name,note
Ada,"line one
line two"

This is why manual string concatenation is unsafe for CSV.

Avoid manual CSV building ​

Avoid this:

cpp
std::string output;

output += name;
output += ",";
output += language;
output += "\n";

This breaks when fields contain:

txt
commas
quotes
newlines

Use:

cpp
rixlib::csv::Table table;

table.push_back({name, language});

const auto output = rix.csv.write(table);

Complete export example ​

cpp
#include <rix.hpp>

int main()
{
  rixlib::csv::Table table;

  table.push_back({"id", "name", "project"});
  table.push_back({"1", "Ada", "Rix"});
  table.push_back({"2", "Gaspard", "Vix.cpp"});
  table.push_back({"3", "Grace", "PDF"});

  const auto output = rix.csv.write(table);

  rix.debug.print(output);

  return 0;
}

Run it:

bash
vix run write.cpp

Expected output:

csv
id,name,project
1,Ada,Rix
2,Gaspard,Vix.cpp
3,Grace,PDF

Convert parsed data back to CSV ​

You can parse CSV, inspect or modify the table, then write it again.

cpp
#include <rix.hpp>

#include <string>

int main()
{
  const std::string input =
      "name,project\n"
      "Ada,Rix\n"
      "Gaspard,Vix.cpp\n";

  auto table = rix.csv.parse(input);

  table.push_back({"Grace", "PDF"});

  const auto output = rix.csv.write(table);

  rix.debug.print(output);

  return 0;
}

This is useful for small transformations.

Validate before writing ​

When data comes from outside the program, validate the table before writing it.

cpp
if (table.empty())
{
  rix.debug.eprint("nothing to write");
  return 1;
}

Check row sizes when your output requires a fixed shape:

cpp
for (std::size_t i = 0; i < table.size(); ++i)
{
  if (table[i].size() != 3)
  {
    rix.debug.eprint("invalid row:", i);
    return 1;
  }
}

Then write:

cpp
const auto output = rix.csv.write(table);

Save CSV to a file ​

rix.csv.write(...) returns CSV text.

Use normal C++ file output when you want to save it.

cpp
#include <rix.hpp>

#include <fstream>

int main()
{
  rixlib::csv::Table table;

  table.push_back({"name", "project"});
  table.push_back({"Ada", "Rix"});
  table.push_back({"Gaspard", "Vix.cpp"});

  const auto output = rix.csv.write(table);

  std::ofstream file("report.csv");

  if (!file)
  {
    rix.debug.eprint("failed to open report.csv");
    return 1;
  }

  file << output;

  rix.debug.print("created:", "report.csv");

  return 0;
}

Run it:

bash
vix run write.cpp

This creates:

txt
report.csv

Use in a Vix project ​

Create an application:

bash
vix new csv-write --app
cd csv-write

Add Rix:

bash
vix add rix/rix
vix install

In vix.app, add:

txt
deps = [
  "rix/rix",
]

A small manifest can look like this:

txt
name = "csv-write"
type = "executable"
standard = "c++20"
output_dir = "bin"

sources = [
  "src/main.cpp",
]

include_dirs = [
  "include",
  "src",
]

deps = [
  "rix/rix",
]

packages = [
  "vix",
]

links = [
  "vix::vix",
]

Then use:

cpp
#include <rix.hpp>

int main()
{
  rixlib::csv::Table table;

  table.push_back({"name", "language"});
  table.push_back({"Ada", "C++"});

  const auto output = rix.csv.write(table);

  rix.debug.print(output);

  return 0;
}

Build and run:

bash
vix build
vix run

Single-file usage ​

For small scripts, examples, and experiments:

bash
vix run write.cpp

If Rix is installed globally for single-file usage:

bash
vix install -g rix/rix
vix run write.cpp

For project usage, prefer:

bash
vix add rix/rix
vix install

and keep the dependency in vix.app:

txt
deps = [
  "rix/rix",
]

Facade usage ​

The recommended documentation style is:

cpp
#include <rix.hpp>

Then:

cpp
const auto output = rix.csv.write(table);

This keeps CSV available through the same public object as the other Rix packages:

cpp
rix.csv
rix.debug
rix.auth
rix.pdf

Independent package usage ​

If your project only needs CSV, you can install the independent package:

bash
vix add rix/csv
vix install

In vix.app:

txt
deps = [
  "rix/csv",
]

Then include:

cpp
#include <rix/csv.hpp>

Use this style when you do not need the unified rix.* facade.

Lightweight facade usage ​

If you want the facade style but only want CSV mounted:

cpp
#define RIX_ENABLE_CSV
#include <rix.hpp>

int main()
{
  rixlib::csv::Table table;

  table.push_back({"name", "lang"});
  table.push_back({"Ada", "C++"});

  const auto output = rix.csv.write(table);

  return 0;
}

When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.

Common mistakes ​

Building CSV manually ​

Wrong:

cpp
output += name + "," + language + "\n";

Better:

cpp
table.push_back({name, language});
const auto output = rix.csv.write(table);

Forgetting quoted-field rules ​

These fields need escaping:

txt
Hello, world
She said "hello"
line one
line two

Let the CSV writer handle them.

Forgetting deps ​

For a Vix project, do not put Rix packages in packages.

Use:

txt
deps = [
  "rix/rix",
]

packages is for CMake package discovery.

deps is for Vix Registry packages.

Assuming all rows have the same size ​

CSV can contain rows with different numbers of fields.

Validate the table if your output requires a fixed number of columns.

cpp
if (row.size() != 3)
{
  return 1;
}

What you should remember ​

Create a table:

cpp
rixlib::csv::Table table;

Add rows:

cpp
table.push_back({"name", "language"});
table.push_back({"Ada", "C++"});

Write CSV:

cpp
const auto output = rix.csv.write(table);

Print or save the output:

cpp
rix.debug.print(output);

For a Vix project, install Rix:

bash
vix add rix/rix
vix install

and use:

txt
deps = [
  "rix/rix",
]

Use the writer instead of manual string concatenation.

Validate row sizes when your output expects a fixed schema.

Next step ​

Learn how to use CSV safely with external input.

Next: Safe Access

Released under the MIT License.