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

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

造一個(gè)100w+的示例文件

image.png

引入pom

另外使用了hutool缩举,主打一個(gè)懶人,通通加上匹颤。

 <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>

定義實(shí)體類

實(shí)體類很簡(jiǎn)單仅孩,主要@ExcelProperty和excel文件中屬性對(duì)應(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("班級(jí)")
    private String grade;

    private String fileName;
}

編寫讀取監(jiān)聽

注意:

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

    /**
     * 每隔5條存儲(chǔ)數(shù)據(jù)庫摆尝,實(shí)際使用中可以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,請(qǐng)使用這個(gè)構(gòu)造方法堕汞。每次創(chuàng)建Listener的時(shí)候需要把spring管理的類傳進(jìn)來
     * 由于示例沒有進(jìn)行數(shù)據(jù)庫操作勺爱,這里傳了一個(gè)文件名作為額外參數(shù)示例,傳DAO方法雷同
     *
     * @param fileName
     */
    public StudentReaderListener(String fileName) {
        this.fileName = fileName;
    }

    /**
     * 這個(gè)每一條數(shù)據(jù)解析都會(huì)來調(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 如果需要對(duì)數(shù)據(jù)設(shè)置額外參數(shù)讯检,可以在此處處理,比如創(chuàng)建人琐鲁、創(chuàng)建時(shí)間等等
        data.setFileName(fileName);
        cachedDataList.add(data);

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

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

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

}

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

最終讀取只需要一個(gè)文件對(duì)象即可涝桅,無論是從前端傳來的或者后臺(tái)讀取服務(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冯遂,讀取耗時(shí){}ms",file.length()/1024/1024, end - start);
    }
}

讀取結(jié)果

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


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末向胡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惊完,更是在濱河造成了極大的恐慌僵芹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件小槐,死亡現(xiàn)場(chǎng)離奇詭異拇派,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)凿跳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門件豌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人控嗜,你說我怎么就攤上這事茧彤。” “怎么了疆栏?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵曾掂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我壁顶,道長(zhǎng)珠洗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任若专,我火速辦了婚禮阱州,結(jié)果婚禮上鲁森,老公的妹妹穿的比我還像新娘垛膝。我一直安慰自己惰匙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布匿沛。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪动壤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天淮逻,我揣著相機(jī)與錄音琼懊,去河邊找鬼。 笑死爬早,一個(gè)胖子當(dāng)著我的面吹牛哼丈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筛严,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼醉旦,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了桨啃?” 一聲冷哼從身側(cè)響起车胡,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎照瘾,沒想到半個(gè)月后匈棘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡析命,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年主卫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹃愤。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簇搅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昼浦,到底是詐尸還是另有隱情馍资,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布关噪,位于F島的核電站鸟蟹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏使兔。R本人自食惡果不足惜建钥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望虐沥。 院中可真熱鬧熊经,春花似錦泽艘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至槐壳,卻和暖如春然低,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背务唐。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工雳攘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枫笛。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓吨灭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親刑巧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喧兄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容