DEV Community

Sadiul Hakim
Sadiul Hakim

Posted on

Comprehensive CSV File Handling in Java Tutorial

This tutorial covers CSV file handling using both raw Java and the OpenCSV library.

1. Using Raw Java

Reading CSV Files with Raw Java

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class RawJavaCSVReader {

    public static void main(String[] args) {
        String csvFile = "data.csv";
        String line = "";
        String csvDelimiter = ","; // CSV files typically use comma as delimiter

        List<String[]> data = new ArrayList<>();

        try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {

            // Read the header line (first line)
            String headerLine = br.readLine();
            if (headerLine != null) {
                String[] headers = headerLine.split(csvDelimiter);
                System.out.println("Headers: " + String.join(", ", headers));
            }

            // Read data lines
            while ((line = br.readLine()) != null) {
                // Split the line by comma, handling quoted fields
                String[] values = parseCSVLine(line, csvDelimiter);
                data.add(values);

                // Print the row
                System.out.println("Row: " + String.join(" | ", values));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("Total rows read: " + data.size());
    }

    /**
     * Parses a CSV line, handling quoted fields that may contain commas
     * @param line the CSV line to parse
     * @param delimiter the delimiter character
     * @return array of field values
     */
    private static String[] parseCSVLine(String line, String delimiter) {
        List<String> values = new ArrayList<>();
        StringBuilder currentValue = new StringBuilder();
        boolean inQuotes = false;

        for (int i = 0; i < line.length(); i++) {
            char c = line.charAt(i);

            if (c == '"') {
                // Handle quotes - either start/end of quoted field or escaped quote
                if (inQuotes && i < line.length() - 1 && line.charAt(i + 1) == '"') {
                    // Escaped quote inside quoted field
                    currentValue.append('"');
                    i++; // Skip the next quote
                } else {
                    // Toggle quote state
                    inQuotes = !inQuotes;
                }
            } else if (c == delimiter.charAt(0) && !inQuotes) {
                // Found delimiter outside quotes - end of field
                values.add(currentValue.toString());
                currentValue = new StringBuilder();
            } else {
                // Regular character
                currentValue.append(c);
            }
        }

        // Add the last field
        values.add(currentValue.toString());

        return values.toArray(new String[0]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Writing CSV Files with Raw Java

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class RawJavaCSVWriter {

    public static void main(String[] args) {
        String csvFile = "output.csv";

        // Sample data
        List<String[]> data = Arrays.asList(
            new String[]{"Name", "Age", "City", "Email"},
            new String[]{"John Doe", "30", "New York", "john@example.com"},
            new String[]{"Jane Smith", "25", "London", "jane@example.com"},
            new String[]{"Bob Johnson", "35", "Paris", "bob@example.com"}
        );

        try (BufferedWriter bw = new BufferedWriter(new FileWriter(csvFile))) {

            for (String[] row : data) {
                // Format each row as CSV
                String csvLine = formatAsCSV(row);
                bw.write(csvLine);
                bw.newLine();
            }

            System.out.println("CSV file written successfully: " + csvFile);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Formats an array of values as a CSV line
     * @param values array of field values
     * @return CSV formatted string
     */
    private static String formatAsCSV(String[] values) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < values.length; i++) {
            String value = values[i];

            // Check if value needs quoting (contains comma, quote, or newline)
            boolean needsQuotes = value.contains(",") || value.contains("\"") || value.contains("\n");

            if (needsQuotes) {
                sb.append('"');
                // Escape quotes by doubling them
                sb.append(value.replace("\"", "\"\""));
                sb.append('"');
            } else {
                sb.append(value);
            }

            // Add delimiter unless it's the last value
            if (i < values.length - 1) {
                sb.append(',');
            }
        }

        return sb.toString();
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Using OpenCSV

Setting Up OpenCSV

Add OpenCSV dependency to your project:

Maven:

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.7.1</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Gradle:

implementation 'com.opencsv:opencsv:5.7.1'
Enter fullscreen mode Exit fullscreen mode

Reading CSV Files with OpenCSV

import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class OpenCSVReaderExample {

    public static void main(String[] args) {
        String csvFile = "data.csv";

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(csvFile))
                .withSkipLines(0) // Skip lines if needed (e.g., skip header)
                .build()) {

            // Read all records at once
            List<String[]> allData = reader.readAll();

            // Process each record
            for (int i = 0; i < allData.size(); i++) {
                String[] row = allData.get(i);

                if (i == 0) {
                    System.out.println("Headers: " + String.join(", ", row));
                } else {
                    System.out.println("Row " + i + ": " + String.join(" | ", row));
                }
            }

            System.out.println("Total records: " + allData.size());

        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Reading CSV with Custom Settings

import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class OpenCSVAdvancedReader {

    public static void main(String[] args) {
        String csvFile = "data.csv";

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(csvFile))
                .withCSVParser(new com.opencsv.CSVParserBuilder()
                        .withSeparator(',') // Set custom separator
                        .withQuoteChar('"') // Set custom quote character
                        .withEscapeChar('\\') // Set escape character
                        .build())
                .withSkipLines(1) // Skip header line
                .build()) {

            // Read line by line (better for large files)
            String[] nextLine;
            int rowCount = 0;

            while ((nextLine = reader.readNext()) != null) {
                rowCount++;
                System.out.println("Row " + rowCount + ": " + String.join(" | ", nextLine));

                // Process individual fields
                for (int i = 0; i < nextLine.length; i++) {
                    System.out.println("  Field " + i + ": " + nextLine[i]);
                }
            }

            System.out.println("Total rows processed: " + rowCount);

        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Writing CSV Files with OpenCSV

import com.opencsv.CSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class OpenCSVWriterExample {

    public static void main(String[] args) {
        String csvFile = "output.csv";

        // Sample data
        List<String[]> data = Arrays.asList(
            new String[]{"Name", "Age", "City", "Email"},
            new String[]{"John Doe", "30", "New York", "john@example.com"},
            new String[]{"Jane Smith", "25", "London", "jane@example.com"},
            new String[]{"Bob Johnson", "35", "Paris", "bob@example.com"}
        );

        try (CSVWriter writer = new CSVWriter(new FileWriter(csvFile))) {

            // Write all records at once
            writer.writeAll(data);

            System.out.println("CSV file written successfully: " + csvFile);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Writing CSV with Custom Settings

import com.opencsv.CSVWriter;
import com.opencsv.ICSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;

public class OpenCSVAdvancedWriter {

    public static void main(String[] args) {
        String csvFile = "output_custom.csv";

        try (CSVWriter writer = new CSVWriter(
                new FileWriter(csvFile),
                ';', // Custom separator (semicolon instead of comma)
                ICSVWriter.DEFAULT_QUOTE_CHARACTER,
                ICSVWriter.DEFAULT_ESCAPE_CHARACTER,
                ICSVWriter.DEFAULT_LINE_END)) {

            // Write header
            writer.writeNext(new String[]{"ID", "Product", "Price", "Description"});

            // Write data rows
            writer.writeNext(new String[]{"1", "Laptop", "999.99", "High-performance laptop"});
            writer.writeNext(new String[]{"2", "Mouse", "25.50", "Wireless optical mouse"});
            writer.writeNext(new String[]{"3", "Keyboard", "75.00", "Mechanical gaming keyboard"});

            // Write a row with special characters that need quoting
            writer.writeNext(new String[]{"4", "Monitor, 24\"", "200.00", "24-inch monitor, with stand"});

            System.out.println("Custom CSV file written successfully: " + csvFile);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Mapping CSV to Java Objects with OpenCSV

import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

// Define a Java bean class that matches CSV structure
class Person {
    private String name;
    private int age;
    private String city;
    private String email;

    // Default constructor required by OpenCSV
    public Person() {}

    // Parameterized constructor
    public Person(String name, int age, String city, String email) {
        this.name = name;
        this.age = age;
        this.city = city;
        this.email = email;
    }

    // Getters and setters (required by OpenCSV)
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }

    public String getCity() { return city; }
    public void setCity(String city) { this.city = city; }

    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", city='" + city + "', email='" + email + "'}";
    }
}

public class OpenCSVBeanExample {

    public static void main(String[] args) {
        String csvFile = "people.csv";

        try (FileReader reader = new FileReader(csvFile)) {

            // Create mapping strategy
            HeaderColumnNameMappingStrategy<Person> strategy = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(Person.class);

            // Create CSV to bean converter
            CsvToBean<Person> csvToBean = new CsvToBeanBuilder<Person>(reader)
                    .withMappingStrategy(strategy)
                    .withIgnoreLeadingWhiteSpace(true)
                    .build();

            // Convert CSV to list of Person objects
            List<Person> people = csvToBean.parse();

            // Process the objects
            for (Person person : people) {
                System.out.println(person);
                // You can now work with Person objects instead of raw arrays
                if (person.getAge() > 30) {
                    System.out.println("  -> Over 30 years old");
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Comparison: Raw Java vs OpenCSV

Raw Java Advantages:

  • No external dependencies
  • Full control over parsing logic
  • Good for simple CSV files

Raw Java Disadvantages:

  • Complex to handle edge cases (quoted fields, escaped characters)
  • More code to write and maintain
  • No built-in support for data mapping

OpenCSV Advantages:

  • Handles all CSV edge cases automatically
  • Easy to use API
  • Support for mapping CSV to Java objects
  • Better performance for large files
  • Built-in support for different formats and encodings

OpenCSV Disadvantages:

  • External dependency
  • Less control over low-level parsing

Best Practices

  1. Always handle exceptions properly - CSV files can have various formatting issues
  2. Use try-with-resources to ensure files are properly closed
  3. Validate data - check for null values and data types
  4. Consider file encoding - specify UTF-8 if working with international characters
  5. Use OpenCSV for production code - it handles edge cases better than custom code
  6. For large files, read line by line instead of loading entire file into memory

Top comments (0)