跳转至

Java读取CSV文件为列表:深入解析与实践

简介

在Java开发中,处理CSV(逗号分隔值)文件是一项常见的任务。CSV文件以纯文本形式存储表格数据,每行代表一条记录,字段之间用逗号分隔。将CSV文件读取为列表可以方便地对数据进行处理、分析和进一步操作。本文将详细介绍如何在Java中把CSV文件读取为列表,涵盖基础概念、使用方法、常见实践以及最佳实践。

目录

  1. 基础概念
    • CSV文件结构
    • 列表在Java中的作用
  2. 使用方法
    • 使用BufferedReader和StringTokenizer
    • 使用OpenCSV库
    • 使用Apache Commons CSV
  3. 常见实践
    • 处理表头
    • 处理不同分隔符
    • 处理空值
  4. 最佳实践
    • 性能优化
    • 错误处理
    • 代码可维护性
  5. 小结
  6. 参考资料

基础概念

CSV文件结构

CSV文件是一种简单的文本格式,用于存储表格数据。每一行代表一条记录,字段之间通常用逗号分隔。例如:

姓名,年龄,城市
张三,25,北京
李四,30,上海

列表在Java中的作用

在Java中,列表(List)是一种有序的集合,可以存储多个元素。将CSV文件读取为列表,可以方便地对每一行数据进行遍历、操作和存储。常见的列表实现类有ArrayList和LinkedList。

使用方法

使用BufferedReader和StringTokenizer

这是一种原生的Java方法,通过BufferedReader逐行读取CSV文件,并使用StringTokenizer分割每行数据。

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

public class CSVReaderExample1 {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<List<String>> dataList = new ArrayList<>();

        try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                List<String> row = new ArrayList<>();
                StringTokenizer tokenizer = new StringTokenizer(line, ",");
                while (tokenizer.hasMoreTokens()) {
                    row.add(tokenizer.nextToken());
                }
                dataList.add(row);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (List<String> row : dataList) {
            System.out.println(row);
        }
    }
}

使用OpenCSV库

OpenCSV是一个流行的Java库,用于处理CSV文件。它提供了更简单的API来读取和写入CSV数据。 首先,在项目中添加OpenCSV依赖(如果使用Maven,可以在pom.xml中添加以下依赖):

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>5.7.1</version>
</dependency>

然后,使用OpenCSV读取CSV文件为列表:

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

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

public class CSVReaderExample2 {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<String[]> dataList = new ArrayList<>();

        try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
            dataList = reader.readAll();
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }

        for (String[] row : dataList) {
            for (String cell : row) {
                System.out.print(cell + " ");
            }
            System.out.println();
        }
    }
}

使用Apache Commons CSV

Apache Commons CSV也是一个强大的CSV处理库。 添加Maven依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.9.0</version>
</dependency>

读取CSV文件为列表的代码:

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

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

public class CSVReaderExample3 {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<List<String>> dataList = new ArrayList<>();

        try (CSVParser parser = new CSVParser(new FileReader(csvFilePath), CSVFormat.DEFAULT)) {
            for (CSVRecord record : parser) {
                List<String> row = new ArrayList<>();
                for (String cell : record) {
                    row.add(cell);
                }
                dataList.add(row);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (List<String> row : dataList) {
            System.out.println(row);
        }
    }
}

常见实践

处理表头

通常CSV文件的第一行是表头。可以通过以下方式跳过表头:

// 使用OpenCSV
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

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

public class CSVReaderWithHeader {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<String[]> dataList = new ArrayList<>();

        try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
            reader.skip(1); // 跳过第一行(表头)
            dataList = reader.readAll();
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }

        for (String[] row : dataList) {
            for (String cell : row) {
                System.out.print(cell + " ");
            }
            System.out.println();
        }
    }
}

处理不同分隔符

如果CSV文件使用的分隔符不是逗号,可以在读取时指定分隔符。例如,使用分号作为分隔符:

// 使用Apache Commons CSV
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

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

public class CSVReaderWithDelimiter {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<List<String>> dataList = new ArrayList<>();

        try (CSVParser parser = new CSVParser(new FileReader(csvFilePath), CSVFormat.DEFAULT.withDelimiter(';'))) {
            for (CSVRecord record : parser) {
                List<String> row = new ArrayList<>();
                for (String cell : record) {
                    row.add(cell);
                }
                dataList.add(row);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        for (List<String> row : dataList) {
            System.out.println(row);
        }
    }
}

处理空值

在读取CSV文件时,可能会遇到空值。可以在处理数据时进行判断和处理:

// 使用OpenCSV
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;

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

public class CSVReaderWithNullValues {
    public static void main(String[] args) {
        String csvFilePath = "data.csv";
        List<String[]> dataList = new ArrayList<>();

        try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
            dataList = reader.readAll();
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }

        for (String[] row : dataList) {
            for (String cell : row) {
                if (cell == null || cell.isEmpty()) {
                    System.out.print("NULL ");
                } else {
                    System.out.print(cell + " ");
                }
            }
            System.out.println();
        }
    }
}

最佳实践

性能优化

  • 批量读取:避免逐行读取,可以一次性读取较大的数据块。
  • 使用合适的数据结构:根据数据的特点和操作需求,选择合适的列表实现类。例如,如果需要频繁插入和删除操作,LinkedList可能更合适;如果主要是顺序访问,ArrayList效率更高。

错误处理

  • 异常捕获:在读取CSV文件时,要妥善处理可能出现的异常,如文件不存在、格式错误等。
  • 数据验证:对读取到的数据进行有效性验证,确保数据的准确性和完整性。

代码可维护性

  • 模块化:将CSV读取和处理逻辑封装成独立的方法或类,提高代码的可维护性和复用性。
  • 注释:添加清晰的注释,解释代码的功能和意图,便于他人理解和维护。

小结

本文详细介绍了在Java中读取CSV文件为列表的方法,包括基础概念、使用原生Java方法以及流行的CSV处理库(OpenCSV和Apache Commons CSV)。同时,探讨了常见实践和最佳实践,如处理表头、分隔符、空值,以及性能优化、错误处理和代码可维护性等方面。通过这些内容,读者可以根据具体需求选择合适的方法来高效处理CSV文件数据。

参考资料