Java 導入導出之導出CSV格式文件

一、前言

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章