在 Java 中使用 OpenCSV 操作 CSV 文件

一、什么是CSV

逗号分隔值 (CSV) 文件只是一个普通的纯文本文件,将数据存储在一列一列中,然后用分隔符(如制表符\t,分号等,通常是逗号“,”) 将其拆分,是不同系统之间传输数据的一种常见方式

OpenCSV 是 Java 的 CSV 解析库。OpenCSV 支持您想要执行的所有基本 CSV 类型操作。Java 7 目前是 OpenCSV 的最低支持版本。Java 语言不提供任何本身支持来有效处理 CSV 文件,因此我们使用 OpenCSV 处理 Java 中的 CSV 文件。下面是一个CSV文件的例子:

1,US,United States
2,MY,Malaysia
3,AU,Australia

二、如何在项目中添加 OpenCSV?

  • 对于 maven 项目,您可以在 pom 中包含 OpenCSV maven 依赖项.xml文件。
  <dependency>
     <groupId>com.opencsv</groupId>
     <artifactId>opencsv</artifactId>
     <version>5.3</version>
  </dependency>
  • 于 Gradle 项目,可以包括 OpenCSV 依赖项。
compile group: 'com.opencsv', name: 'opencsv', version: '5.3'
  • 您可以下载OpenCSV Jar 并包括在项目类路径中。

三、OpenCSV的常用类

  • CSVReader – 此类提供将 CSV 文件读取为字符串数组列表的操作。
  • CSVWriter – 此类允许将数据写入 CSV 文件。
  • CsvToBean – 当您想要把 CSV 文件内容填充到 java bean 时,将使用此类。
  • BeanToCsv – 此类有助于将数据从 java 应用程序导出到 CSV 文件。

四、读取 CSV 文件

要读取 CSV 文件,您需要 CSVReader 类。以下是我们将要读取的示例 CSV 文件。

name, rollno, department, result, cgpa
amar, 42, cse, pass, 8.6
rohini, 21, ece, fail, 3.2
aman, 23, cse, pass, 8.9
rahul, 45, ee, fail, 4.6
pratik, 65, cse, pass, 7.2
raunak, 23, me, pass, 9.1
suvam, 68, me, pass, 8.2

我们可以通过两种方式读取 csv 文件:

  • 按行读取数据 :让我们看看如何进行行读取 CSV 文件。为了一行一行地读取数据,首先我们必须通过传递CSV文件的CSVReader 对象来构造和初始化CSVReader对象。之后,我们必须调用 CSVReader 对象的 readNext()方法,以按行读取数据,如下代码所示。
// Java code to illustrate reading a 
// CSV file line by line 
public static void readDataLineByLine(String file) 
{ 

	try { 

		// Create an object of filereader 
		// class with CSV file as a parameter. 
		FileReader filereader = new FileReader(file); 

		// create csvReader object passing 
		// file reader as a parameter 
		CSVReader csvReader = new CSVReader(filereader); 
		String[] nextRecord; 

		// we are going to read data line by line 
		while ((nextRecord = csvReader.readNext()) != null) { 
			for (String cell : nextRecord) { 
				System.out.print(cell + "\t"); 
			} 
			System.out.println(); 
		} 
	} 
	catch (Exception e) { 
		e.printStackTrace(); 
	} 
} 
  • 一次读取所有数据:我们使用 readNext() 方法一个一个的读取 CSV 记录。CSVReader 还提供一种称为 readAll() 的方法,用于一次将所有记录读取到列表中。
 List allData = csvReader.readAll(); 

默认情况下,当我们读取 csv 文件时,不会忽略标头。当我们需要跳过列表中的第一个元素时,我们可以在创建 CSVReader 时指定开始行。

CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build();

代码:

// Java code to illustrate reading a 
// all data at once 
public static void readAllDataAtOnce(String file) 
{ 
	try { 
		// Create an object of file reader 
		// class with CSV file as a parameter. 
		FileReader filereader = new FileReader(file); 

		// create csvReader object and skip first Line 
		CSVReader csvReader = new CSVReaderBuilder(filereader) 
								.withSkipLines(1) 
								.build(); 
		List<String[]> allData = csvReader.readAll(); 

		// print Data 
		for (String[] row : allData) { 
			for (String cell : row) { 
				System.out.print(cell + "\t"); 
			} 
			System.out.println(); 
		} 
	} 
	catch (Exception e) { 
		e.printStackTrace(); 
	} 
} 

使用不同的分隔符读取 CSV 文件

CSV 文件可以用逗号以外的分隔符分隔,例如分号、冒号等。下面的示例演示如何读取 CSV 文件的数据,该文件用分号字符分隔。
分号分隔 CSV 文件示例:

name;rollno;department;result;cgpa
amar;42;cse;pass;8.6
rohini;21;ece;fail;3.2
aman;23;cse;pass;8.9
rahul;45;ee;fail;4.6
pratik;65;cse;pass;7.2
raunak;23;me;pass;9.1
suvam;68;me;pass;8.2

对于自定义分隔符,将创建具有特定解析器字符的第一个 CSVParser。

CSVParser parser = new CSVParserBuilder().withSeparator(';').build();

然后,我们将使用CSVParser()方法创建CSVReader对象,并提供了与CSVParser方法的参数的解析器对象。最后调用生成方法生成对象。

CSVReader csvReader = new CSVReaderBuilder(filereader).withCSVParser(parser).build();

代码:

// Java code to illustrate 
// Reading CSV File with different separator 
public static void readDataFromCustomSeperator(String file) 
{ 
	try { 
		// Create an object of file reader class with CSV file as a parameter. 
		FileReader filereader = new FileReader(file); 

		// create csvParser object with 
		// custom seperator semi-colon 
		CSVParser parser = new CSVParserBuilder().withSeparator(';').build(); 

		// create csvReader object with parameter 
		// filereader and parser 
		CSVReader csvReader = new CSVReaderBuilder(filereader) 
								.withCSVParser(parser) 
								.build(); 

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

		// Print Data. 
		for (String[] row : allData) { 
			for (String cell : row) { 
				System.out.print(cell + "\t"); 
			} 
			System.out.println(); 
		} 
	} 
	catch (Exception e) { 
		e.printStackTrace(); 
	} 
} 

示例 – 读取两个 csv 文件result.csv 和 results_semicolon_Seperator.csv
result.csv具有默认分隔符','results_semicolon_Seperator.csv使用的是分隔符';''代替','。
代码:

// Java program to illustrate reading 
// two CSV files 
// with different seperators 

import java.io.FileReader; 
import java.util.List; 
import com.opencsv.*; 

public class ReadCSVData { 
	private static final String CSV_FILE_PATH 
		= "D:\\EclipseWorkSpace\\CSVOperations\\results.csv"; 
	private static final String CSV_FILE_CUSTOM_SEPERATOR 
		= "D:\\EclipseWorkSpace\\CSVOperations\\results_semicolon_Seperator.csv"; 

	public static void main(String[] args) 
	{ 

		System.out.println("Read Data Line by Line With Header \n"); 
		readDataLineByLine(CSV_FILE_PATH); 
		System.out.println("_______________________________________________"); 

		System.out.println("Read All Data at Once and Hide the Header also \n"); 
		readAllDataAtOnce(CSV_FILE_PATH); 
		System.out.println("_______________________________________________"); 

		System.out.println("Custom Seperator here semi-colon\n"); 
		readDataFromCustomSeperator(CSV_FILE_CUSTOM_SEPERATOR); 
		System.out.println("_______________________________________________"); 
	} 

	public static void readDataLineByLine(String file) 
	{ 

		try { 

			// Create an object of filereader class 
			// with CSV file as a parameter. 
			FileReader filereader = new FileReader(file); 

			// create csvReader object passing 
			// filereader as parameter 
			CSVReader csvReader = new CSVReader(filereader); 
			String[] nextRecord; 

			// we are going to read data line by line 
			while ((nextRecord = csvReader.readNext()) != null) { 
				for (String cell : nextRecord) { 
					System.out.print(cell + "\t"); 
				} 
				System.out.println(); 
			} 
		} 
		catch (Exception e) { 
			e.printStackTrace(); 
		} 
	} 

	public static void readAllDataAtOnce(String file) 
	{ 
		try { 

			// Create an object of filereader class 
			// with CSV file as a parameter. 
			FileReader filereader = new FileReader(file); 

			// create csvReader object 
			// and skip first Line 
			CSVReader csvReader = new CSVReaderBuilder(filereader) 
									.withSkipLines(1) 
									.build(); 
			List<String[]> allData = csvReader.readAll(); 

			// print Data 
			for (String[] row : allData) { 
				for (String cell : row) { 
					System.out.print(cell + "\t"); 
				} 
				System.out.println(); 
			} 
		} 
		catch (Exception e) { 
			e.printStackTrace(); 
		} 
	} 

	public static void readDataFromCustomSeperator(String file) 
	{ 
		try { 
			// Create object of filereader 
			// class with csv file as parameter. 
			FileReader filereader = new FileReader(file); 

			// create csvParser object with 
			// custom seperator semi-colon 
			CSVParser parser = new CSVParserBuilder().withSeparator(';').build(); 

			// create csvReader object with 
			// parameter filereader and parser 
			CSVReader csvReader = new CSVReaderBuilder(filereader) 
									.withCSVParser(parser) 
									.build(); 

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

			// print Data 
			for (String[] row : allData) { 
				for (String cell : row) { 
					System.out.print(cell + "\t"); 
				} 
				System.out.println(); 
			} 
		} 
		catch (Exception e) { 
			e.printStackTrace(); 
		} 
	} 
} 

输出:

_______________________________________________
Read Data Line by Line With Header 

name    rollno    department    result    cgpa    
amar    42    cse    pass    8.6    
rohini    21    ece    fail    3.2    
aman    23    cse    pass    8.9    
rahul    45    ee    fail    4.6    
pratik    65    cse    pass    7.2    
raunak    23    me    pass    9.1    
suvam    68    me    pass    8.2    
_______________________________________________
Read All Data at Once and Hide the Header also 

amar    42    cse    pass    8.6    
rohini    21    ece    fail    3.2    
aman    23    cse    pass    8.9    
rahul    45    ee    fail    4.6    
pratik    65    cse    pass    7.2    
raunak    23    me    pass    9.1    
suvam    68    me    pass    8.2    
_______________________________________________
Custom Seperator here semi-colon

name    rollno    department    result    cgpa    
amar    42    cse    pass    8.6    
rohini    21    ece    fail    3.2    
aman    23    cse    pass    8.9    
rahul    45    ee    fail    4.6    
pratik    65    cse    pass    7.2    
raunak    23    me    pass    9.1    
suvam    68    me    pass    8.2    
_______________________________________________

五、写入 CSV 文件

写入 CSV 文件就像读取一样简单。通过将 FileWriter 对象作为参数传递,然后开始使用 CSVWrite 类的方法将数据写入 CSV 文件,创建 CSVWriter 实例。写入数据后,我们需要通过调用 CSVWriter 类的 close() 方法来关闭 CSVWriter 连接。

  • 按行写入数据 – CSVWriter 可以使用 writeNext() 方法一行一行写入,其中字符串数组以每个逗号分隔元素作为单独的输入传递。
    代码:
  • public static void writeDataLineByLine(String filePath) 
    { 
    	// first create file object for file placed at location 
    	// specified by filepath 
    	File file = new File(filePath); 
    	try { 
    		// create FileWriter object with file as parameter 
    		FileWriter outputfile = new FileWriter(file); 
    
    		// create CSVWriter object filewriter object as parameter 
    		CSVWriter writer = new CSVWriter(outputfile); 
    
    		// adding header to csv 
    		String[] header = { "Name", "Class", "Marks" }; 
    		writer.writeNext(header); 
    
    		// add data to csv 
    		String[] data1 = { "Aman", "10", "620" }; 
    		writer.writeNext(data1); 
    		String[] data2 = { "Suraj", "10", "630" }; 
    		writer.writeNext(data2); 
    
    		// closing writer connection 
    		writer.close(); 
    	} 
    	catch (IOException e) { 
    		// TODO Auto-generated catch block 
    		e.printStackTrace(); 
    	} 
    } 
    

    输出:结果.csv以下数据的文件

    "Name", "Class", "Marks"
    "Aman", "10", "620"
    "Suraj", "10", "630"
  • 一次写入所有数据 - 对于一次性写入调用 CSVWriter 类的writeAll()方法,将 String[] 列表作为参数传递,每个 String[]表示文件的一行。
    代码:
  • public static void writeDataAtOnce(String filePath) 
    { 
    
    	// first create file object for file placed at location 
    	// specified by filepath 
    	File file = new File(filePath); 
    
    	try { 
    		// create FileWriter object with file as parameter 
    		FileWriter outputfile = new FileWriter(file); 
    
    		// create CSVWriter object filewriter object as parameter 
    		CSVWriter writer = new CSVWriter(outputfile); 
    
    		// create a List which contains String array 
    		List<String[]> data = new ArrayList<String[]>(); 
    		data.add(new String[] { "Name", "Class", "Marks" }); 
    		data.add(new String[] { "Aman", "10", "620" }); 
    		data.add(new String[] { "Suraj", "10", "630" }); 
    		writer.writeAll(data); 
    
    		// closing writer connection 
    		writer.close(); 
    	} 
    	catch (IOException e) { 
    		// TODO Auto-generated catch block 
    		e.printStackTrace(); 
    	} 
    } 

    输出:

    "Name", "Class", "Marks"
    "Aman", "10", "620"
    "Suraj", "10", "630"

    使用不同的分隔符写 CSV 文件

    默认情况下,CSV 的分隔符将是逗号"," 。如果要将另一个字符作为分隔符,以便它可以作为参数传递给 CSVWriter 类。

    Syntax :
    CSVWriter(Writer writer, char separator, char quotechar,
                                  char escapechar, String lineEnd)
    Description : Constructs CSVWriter with supplied separator,
    quote char, escape char and line ending.
    

    代码:

    public static void writeDataForCustomSeperatorCSV(String filePath) 
    { 
    
    	// first create file object for file placed at location 
    	// specified by filepath 
    	File file = new File(filePath); 
    
    	try { 
    		// create FileWriter object with file as parameter 
    		FileWriter outputfile = new FileWriter(file); 
    
    		// create CSVWriter with '|' as separator 
    		CSVWriter writer = new CSVWriter(outputfile, '|', 
    										CSVWriter.NO_QUOTE_CHARACTER, 
    										CSVWriter.DEFAULT_ESCAPE_CHARACTER, 
    										CSVWriter.DEFAULT_LINE_END); 
    
    		// create a List which contains String array 
    		List<String[]> data = new ArrayList<String[]>(); 
    		data.add(new String[] { "Name", "Class", "Marks" }); 
    		data.add(new String[] { "Aman", "10", "620" }); 
    		data.add(new String[] { "Suraj", "10", "630" }); 
    		writer.writeAll(data); 
    
    		// closing writer connection 
    		writer.close(); 
    	} 
    	catch (IOException e) { 
    		// TODO Auto-generated catch block 
    		e.printStackTrace(); 
    	} 
    } 

    输出:result.csv文件的数据如下

    Name|Class|Marks
    Aman|10|620
    Suraj|10|630
    

    示例:
    让我们创建 一个java 程序,该程序生成分号分隔的 csv 文件,并包含作为Input提供的数据。

    Input:
    Enter no of rows
    9
    Enter Data
    Name Class Marks
    Aman 10 543
    Amar 10 541
    Sanjeet 10 555
    Luv 10 580
    Ranjeet 10 512
    Rabi 10 540
    Dev 10 333
    Sunny 10 198
    

    代码:

    // Java program to illustrate 
    // for Writing Data in CSV file 
    import java.io.*; 
    import java.util.*; 
    import com.opencsv.CSVWriter; 
    
    public class ResultGenerator { 
    	private static final String CSV_FILE_PATH 
    		= "./result.csv"; 
    	public static void main(String[] args) 
    	{ 
    		addDataToCSV(CSV_FILE_PATH); 
    	} 
    	public static void addDataToCSV(String output) 
    	{ 
    		// first create file object for file placed at location 
    		// specified by filepath 
    		File file = new File(output); 
    		Scanner sc = new Scanner(System.in); 
    		try { 
    			// create FileWriter object with file as parameter 
    			FileWriter outputfile = new FileWriter(file); 
    
    			// create CSVWriter with ';' as separator 
    			CSVWriter writer = new CSVWriter(outputfile, ';', 
    											CSVWriter.NO_QUOTE_CHARACTER, 
    											CSVWriter.DEFAULT_ESCAPE_CHARACTER, 
    											CSVWriter.DEFAULT_LINE_END); 
    
    			// create a List which contains Data 
    			List<String[]> data = new ArrayList<String[]>(); 
    
    			System.out.println("Enter no of rows"); 
    			int noOfRow = Integer.parseInt(sc.nextLine()); 
    			System.out.println("Enter Data"); 
    			for (int i = 0; i < noOfRow; i++) { 
    				String row = sc.nextLine(); 
    				String[] rowdata = row.split(" "); 
    				data.add(rowdata); 
    			} 
    
    			writer.writeAll(data); 
    
    			// closing writer connection 
    			writer.close(); 
    		} 
    		catch (IOException e) { 
    			// TODO Auto-generated catch block 
    			e.printStackTrace(); 
    		} 
    	} 
    } 

    输出:下面是result.csv文件的数据

    Name;Class;Marks
    Aman;10;543
    Amar;10;541
    Sanjeet;10;555
    Luv;10;580
    Ranjeet;10;512
    Rabi;10;540
    Dev;10;333
    Sunny;10;198

    第六、踩坑[奸笑]

    代码执行到CSVReader csvReader = new CSVReader(filereader);的时候就报错:

    java.lang.ClassNotFoundException: org.apache.commons.lang3.ObjectUtils

    报错很清楚,就是缺少了ObjectUtils这个类。您可以如下操作:

    在gradle依赖中加上下面这个依赖,重新编译就可以了。

    • 对于 maven 项目,您可以添加依赖项。
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.11</version>
    </dependency>
    • 对于 Gradle 项目,可以包括下面这个依赖,重新编译就可以了
    compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
    • 您也可以下载 Jar 并包括在项目类路径中。

    https://commons.apache.org/proper/commons-lang/download_lang.cgi

    完事收工[奸笑]

    原文链接:,转发请注明来源!