一、前言
之前一直使用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,引入項目即可。