EasyExcel讀取excel(大數(shù)據(jù)量不會崩哦~)

導(dǎo)入excel作為日常開發(fā)中最最最常見的需求,可以簡單做、也可以復(fù)雜做,也有很多很多的成形框架可以用,比如easyexcel、easypoi、jxls等等,各有優(yōu)劣,大家可以根據(jù)業(yè)務(wù)要求進行選擇。本文給出一個大數(shù)據(jù)量下讀取excel的示例,若有需要,可以取源碼參考。

造一個100w+的示例文件

image.png

引入pom

另外使用了hutool,主打一個懶人,通通加上。

 <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>4.0.3</version>
        </dependency>
 <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>

定義實體類

實體類很簡單,主要@ExcelProperty和excel文件中屬性對應(yīng)即可

@Data
public class StudentInfo implements Serializable  {

    private static final long serialVersionUID = 1L;

    private String id;

    @ExcelProperty("姓名")
    private String name;

    @ExcelProperty("年齡")
    private int age;

    @ExcelProperty("性別")
    private String gender;

    @ExcelProperty("班級")
    private String grade;

    private String fileName;
}

編寫讀取監(jiān)聽

注意:

  • 注釋里的TODO,需要根據(jù)自己的業(yè)務(wù)進行補充,本文只寫了讀取excel,沒有做數(shù)據(jù)存儲
  • 全部讀取完的回調(diào)方法里需要再保存一次,否則最后一次讀取的會漏存;
  • invoke方法里可以執(zhí)行自己對讀取數(shù)據(jù)的其他操作,比如補充其他屬性、對象轉(zhuǎn)換等等
@Slf4j
public class StudentReaderListener implements ReadListener<StudentInfo> {

    /**
     * 每隔5條存儲數(shù)據(jù)庫,實際使用中可以100條,然后清理list ,方便內(nèi)存回收
     */
    private static final int BATCH_COUNT = 10000;
    /**
     * 緩存的數(shù)據(jù)
     */
    private List<StudentInfo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    private String fileName;


    /**
     * 如果使用了spring,請使用這個構(gòu)造方法。每次創(chuàng)建Listener的時候需要把spring管理的類傳進來
     * 由于示例沒有進行數(shù)據(jù)庫操作,這里傳了一個文件名作為額外參數(shù)示例,傳DAO方法雷同
     *
     * @param fileName
     */
    public StudentReaderListener(String fileName) {
        this.fileName = fileName;
    }

    /**
     * 這個每一條數(shù)據(jù)解析都會來調(diào)用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(StudentInfo data, AnalysisContext context) {
//        log.info("解析到一條數(shù)據(jù):{}", JSONUtil.toJsonStr(data));

        // TODO 如果需要對數(shù)據(jù)設(shè)置額外參數(shù),可以在此處處理,比如創(chuàng)建人、創(chuàng)建時間等等
        data.setFileName(fileName);
        cachedDataList.add(data);

        // 達到BATCH_COUNT了,需要去存儲一次數(shù)據(jù)庫,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內(nèi)存,容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存儲完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有數(shù)據(jù)解析完成了 都會來調(diào)用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲到數(shù)據(jù)庫
        saveData();
        log.info("所有數(shù)據(jù)解析完成!");
    }

    /**
     * 加上存儲數(shù)據(jù)庫
     */
    private void saveData() {
        log.info("{}條數(shù)據(jù),開始存儲數(shù)據(jù)庫!", cachedDataList.size());
        //todo 執(zhí)行保存邏輯
        log.info("存儲數(shù)據(jù)庫成功!");
    }

}

main方法(可以改造到你的controller或者service)

最終讀取只需要一個文件對象即可,無論是從前端傳來的或者后臺讀取服務(wù)器上的均可。

public class EasyExcelDemo {

    private static final Logger log = LoggerFactory.getLogger(EasyExcelDemo.class);

    public static void main(String[] args) {
        ClassLoader classLoader = EasyExcelDemo.class.getClassLoader();
        URL resourceUrl = classLoader.getResource("demo/student.xlsx");
        File file = new File(resourceUrl.getFile());
        long start = System.currentTimeMillis();
        EasyExcel.read(file.getAbsoluteFile(), StudentInfo.class,
                        new StudentReaderListener(file.getName()))
                .sheet().doRead();
        long end = System.currentTimeMillis();
        log.info("文件大?。簕}Mb,讀取耗時{}ms",file.length()/1024/1024, end - start);
    }
}

讀取結(jié)果

104w數(shù)據(jù),16M大小,讀取耗時大約8s。也試過47Mb大小文件,帶入庫約2min30s,根據(jù)數(shù)據(jù)量大小時間會有不同,但是由于此方法是一條一條讀取,然后一批一批處理,不會把所有數(shù)據(jù)加到內(nèi)存,因此不會OOM,除非每批數(shù)據(jù)量設(shè)置特別大或者你的內(nèi)存特別小。


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容