Try it yourself with our free Json To Csv tool — runs entirely in your browser, no signup needed.

How to Parse CSV in Dart

How to Parse CSV in Dart

Parsing CSV (Comma Separated Values) files is a common task in software development, and Dart is no exception. Whether you're working with data imports, exports, or processing large datasets, being able to parse CSV files efficiently is crucial. In this guide, we'll walk through the process of parsing CSV files in Dart, covering the basics, edge cases, common mistakes, and performance tips.

Quick Example

Here's a minimal example of how to parse a CSV file in Dart:

import 'package:csv/csv.dart';

void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK';

  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);

  for (var row in csvTable) {
    print(row);
  }
}

This code uses the csv package, which can be installed by adding the following dependency to your pubspec.yaml file:

dependencies:
  csv: ^5.0.1

Then, run flutter pub get or dart pub get to install the package.

Step-by-Step Breakdown

Let's break down the code:

  1. import 'package:csv/csv.dart';: We import the csv package, which provides the CsvToListConverter class.
  2. String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK';: We define a sample CSV string.
  3. List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);: We create a CsvToListConverter instance and use its convert method to parse the CSV string into a list of lists. Each inner list represents a row in the CSV table.
  4. for (var row in csvTable) { print(row); }: We iterate over the rows and print each one.

Handling Edge Cases

Empty/Null Input

What happens when the input CSV string is empty or null? Let's test it:

void main() {
  String? csvData = null;

  try {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData!);
  } on ArgumentError catch (e) {
    print(e); // "Invalid argument(s): input is null"
  }
}

In this case, the convert method throws an ArgumentError because it expects a non-null input. We can add a simple null check to handle this:

void main() {
  String? csvData = null;

  if (csvData != null) {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
    // ...
  } else {
    print("Input is null or empty");
  }
}

Invalid Input

What if the input CSV string is malformed? For example:

void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK,Extra,Column';

  try {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
  } on FormatException catch (e) {
    print(e); // "Invalid format: extra columns"
  }
}

In this case, the convert method throws a FormatException because the input CSV string has an inconsistent number of columns. We can add a try-catch block to handle this:

void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK,Extra,Column';

  try {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
    // ...
  } on FormatException catch (e) {
    print("Invalid input format: ${e.message}");
  }
}

Large Input

What if the input CSV string is very large? We can use a Stream to process the CSV data in chunks:

import 'dart:io';
import 'package:csv/csv.dart';

void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK';

  final csvStream = csvData.split('\n').map((row) => row.split(',')).asStream();

  csvStream.listen((row) {
    print(row);
  });
}

This approach can help reduce memory usage when dealing with large CSV files.

Unicode/Special Characters

What if the input CSV string contains Unicode or special characters? The csv package supports Unicode characters out of the box:

void main() {
  String csvData = 'Name,Åge,Country\nJohn,25,USA\nAlice,30,UK';

  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);

  for (var row in csvTable) {
    print(row);
  }
}

No special handling is required.

Common Mistakes

1. Forgetting to import the csv package

// Wrong
void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK';
  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
}

// Correct
import 'package:csv/csv.dart';
void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK';
  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
}

2. Not handling null or empty input

// Wrong
void main() {
  String? csvData = null;
  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData!);
}

// Correct
void main() {
  String? csvData = null;
  if (csvData != null) {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
    // ...
  } else {
    print("Input is null or empty");
  }
}

3. Not handling invalid input format

// Wrong
void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK,Extra,Column';
  List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
}

// Correct
void main() {
  String csvData = 'Name,Age,Country\nJohn,25,USA\nAlice,30,UK,Extra,Column';
  try {
    List<List<dynamic>> csvTable = const CsvToListConverter().convert(csvData);
    // ...
  } on FormatException catch (e) {
    print("Invalid input format: ${e.message}");
  }
}

Performance Tips

1. Use a Stream for large input

Processing large CSV files can be memory-intensive. Using a Stream to process the data in chunks can help reduce memory usage.

2. Avoid unnecessary conversions

When working with large datasets, avoid converting the entire CSV table to a list of lists. Instead, process the data in chunks using a Stream.

3. Use a CsvToListConverter instance

Creating a new CsvToListConverter instance for each conversion can be inefficient. Create a single instance and reuse it for multiple conversions.

FAQ

Q: What is the best way to handle null or empty input?

A: Use a null check and handle the case where the input is null or empty.

Q: How do I handle invalid input format?

A: Use a try-catch block to catch FormatException and handle the error accordingly.

Q: Can I use the csv package with large input?

A: Yes, use a Stream to process the data in chunks to reduce memory usage.

Q: Does the csv package support Unicode characters?

A: Yes, the csv package supports Unicode characters out of the box.

Q: What is the best way to optimize performance when parsing CSV files?

A: Use a Stream to process the data in chunks, avoid unnecessary conversions, and reuse a CsvToListConverter instance.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp