一、前言
之前一直使用POI导出Excel文件,发现已经不满足需求了,后来了解CSV之后,发现速度快的飞起,决定把项目中的改成CSV的方式,这里记录下过程,把坑填一下,参考大佬文章:https://www.cnblogs.com/cjsblog/p/9260421.html。测试源码和jar都已经上传到了CSDN下载,有需要的同学,可以直接前往下载:https://download.csdn.net/download/wjhsmart/11045070
二、准备工作
使用到的jar,maven代码,如果是使用jar,可以前往:https://mvnrepository.com 下载相应的jar
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
三、测试代码
直接把下面代码复制到测试类中,对每个方法就可以运行
package com.junit.csv;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Before;
import org.junit.Test;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCSV {
/**
* 测试输出到csv
* @throws Exception
*/
@Test
public void testWrite() throws Exception {
FileOutputStream fos = new FileOutputStream("/Users/weijinhui/Downloads/test.csv");
OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader("姓名", "年龄", "家乡", "性别");
CSVPrinter csvPrinter = new CSVPrinter(osw, csvFormat);
// 第二种方式设置头部信息
// csvPrinter = CSVFormat.DEFAULT.withHeader("姓名", "年龄", "家乡", "性别").print(osw);
for (int i = 0; i < 10; i++) {
csvPrinter.printRecord("张三", 20, "上海", "男");
}
csvPrinter.flush();
csvPrinter.close();
}
/**
* 测试读取
* @throws IOException
*/
@Test
public void testRead() throws IOException {
InputStream is = new FileInputStream("/Users/weijinhui/Downloads/test.csv");
InputStreamReader isr = new InputStreamReader(is, "UTF8");
Reader reader = new BufferedReader(isr);
CSVParser parser = CSVFormat.EXCEL.withHeader("name", "age", "jia", "gender").parse(reader);
// CSVParser csvParser = CSVParser.parse(reader, CSVFormat.DEFAULT.withHeader("name", "age", "jia"));
List<CSVRecord> list = parser.getRecords();
for (CSVRecord record : list) {
System.out.println(record.getRecordNumber()
+ ":" + record.get("name")
+ ":" + record.get("age")
+ ":" + record.get("jia")
+ ":" + record.get("gender"));
}
parser.close();
}
/**
* 分析Excel csv文件
*/
@Test
public void testParse() throws Exception {
Reader reader = new FileReader("/Users/weijinhui/Downloads/test.csv");
CSVParser parser = CSVFormat.EXCEL.parse(reader);
for (CSVRecord record : parser.getRecords()) {
System.out.println(record);
}
parser.close();
}
/**
* 手动定义标题
*/
@Test
public void testParseWithHeader() throws Exception {
Reader reader = new FileReader("/Users/weijinhui/Downloads/test.csv");
CSVParser parser = CSVFormat.EXCEL.withHeader("id", "name", "code", "gender").parse(reader);
for (CSVRecord record : parser.getRecords()) {
System.out.println(record.get("id") + ","
+ record.get("name") + ","
+ record.get("code")
+ record.get("gender"));
}
parser.close();
}
/**
* 使用枚举定义头
*/
enum MyHeaderEnum {
ID, NAME, CODE, GENDER;
}
/**
* 测试使用枚举定义头部
* @throws Exception
*/
@Test
public void testParseWithEnum() throws Exception {
Reader reader = new FileReader("/Users/weijinhui/Downloads/test.csv");
CSVParser parser = CSVFormat.EXCEL.withHeader(MyHeaderEnum.class).parse(reader);
for (CSVRecord record : parser.getRecords()) {
System.out.println(record.get(MyHeaderEnum.ID) + ","
+ record.get(MyHeaderEnum.NAME) + ","
+ record.get(MyHeaderEnum.CODE) + ","
+ record.get(MyHeaderEnum.GENDER));
}
parser.close();
}
private List<Map<String, String>> recordList = new ArrayList<>();
/**
* 初始化list
*/
@Before
public void init() {
for (int i = 0; i < 5; i++) {
Map<String, String> map = new HashMap<>();
map.put("name", "zhangsan");
map.put("code", "001");
recordList.add(map);
}
}
/**
* 测试使用线程生成多个文件,模拟导出
* @throws InterruptedException
*/
@Test
public void writeMuti() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
CountDownLatch doneSignal = new CountDownLatch(2);
executorService.submit(new exprotThread("/Users/weijinhui/Downloads/0.csv", recordList, doneSignal));
executorService.submit(new exprotThread("/Users/weijinhui/Downloads/1.csv", recordList, doneSignal));
doneSignal.await();
System.out.println("Finish!!!");
}
/**
* 定义导出线程
*/
class exprotThread implements Runnable {
private String filename;
private List<Map<String, String>> list;
private CountDownLatch countDownLatch;
public exprotThread(String filename, List<Map<String, String>> list, CountDownLatch countDownLatch) {
this.filename = filename;
this.list = list;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
CSVPrinter printer = new CSVPrinter(new FileWriter(filename), CSVFormat.EXCEL.withHeader("NAME", "CODE"));
for (Map<String, String> map : list) {
printer.printRecord(map.values());
}
printer.close();
countDownLatch.countDown();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 测试写100万数据需要花费多长时间
*/
@Test
public void testMillion() throws Exception {
int times = 10000 * 10;
Object[] cells = {"满100减15元", "100011", 15};
// 导出为CSV文件
long t1 = System.currentTimeMillis();
FileWriter writer = new FileWriter("/Users/weijinhui/Downloads/test1.csv");
CSVPrinter printer = CSVFormat.EXCEL.print(writer);
for (int i = 0; i < times; i++) {
printer.printRecord(cells);
}
printer.flush();
printer.close();
long t2 = System.currentTimeMillis();
System.out.println("CSV: " + (t2 - t1));
// 导出为Excel文件
long t3 = System.currentTimeMillis();
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet();
for (int i = 0; i < times; i++) {
XSSFRow row = sheet.createRow(i);
for (int j = 0; j < cells.length; j++) {
XSSFCell cell = row.createCell(j);
cell.setCellValue(String.valueOf(cells[j]));
}
}
FileOutputStream fos = new FileOutputStream("/Users/weijinhui/Downloads/test2.xlsx");
workbook.write(fos);
fos.flush();
fos.close();
long t4 = System.currentTimeMillis();
System.out.println("Excel: " + (t4 - t3));
}
}
附上测试 CSV 和 Excel 导出结果截图,会发现,CSV 何止是快的飞起,简直是快的不要不要的
四、遇到的坑
运行测试方法报下面的错误:java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.junit.internal.builders.JUnit4Builder.runnerForClass(JUnit4Builder.java:10)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:44)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.ClassNotFoundException: org.hamcrest.SelfDescribing
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 25 more
这是junit 4.1.1中没有hamcrest包了,如果遇到相同问题的同学,可以直接使用:http://central.maven.org/maven2/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar,点击链接可以直接下载jar,引入项目即可。