【问题标题】:Write 1 Million record from XLS file to CVS file in Java用 Java 将 100 万条记录从 XLS 文件写入 CSV 文件
【发布时间】:2020-03-18 22:44:31
【问题描述】:

我的项目中有一个场景,用户上传具有 100 万条记录的 XLS 文件,我需要将此 xls 文件转换为 csv 文件,然后 sql server 作业将处理 csv 文件。

我有一个将 xls 文件转换为 csv 的过程 - 但是当我在 PCF 中部署此代码时,它开始抛出堆内存错误。我在本地环境中也遇到了同样的错误。

代码快照:

String inputFileName = "UserInput.xls";

FileInputStream input_document = new FileInputStream(new File(inputFileName));
Workbook my_xls_workbook = StreamingReader.builder().open(input_document);//this line throws out of memory error.
Sheet sheet = my_xls_workbook.getSheetAt(0);

......剩余代码读取工作表对象并执行转换。

【问题讨论】:

  • StreamingReader 不在 Java 标准库中...请提供理解您的代码所需的完整类名(或导入)。
  • 尝试使用open(File) 而不是open(InputStream)
  • @Andreas 这无济于事,运行的是相同的代码...查看源代码:github.com/monitorjbl/excel-streaming-reader/blob/master/src/…
  • 好吧,尝试直接使用 POI 的SXSSF,以便很好地流式传输读取数据。
  • 是的......这个库 OP 正在使用似乎将整个东西加载到内存中,所以这个名字很糟糕,因为它暗示你可以进行流解析(除了下一个元素)但你真的不能从我在源代码中看到的内容。

标签: java excel heap-memory file-conversion pcf


【解决方案1】:

在问题上附加一些上下文总是更好的(例如,你有多少内存,你给 JVM 多少内存,你得到的错误)

话虽如此,我在黑暗中的镜头是你应该给 JVM 更多的内存,比如

java .... -Xms4g -Xmx4g ...

有关这些参数的更多详细信息,请参阅此问题 [1]。


[1]What are the -Xms and -Xmx parameters when starting JVM?

【讨论】:

    【解决方案2】:

    您用于将文件加载到工作簿中的方法似乎很急切,即它只会将整个文档读入内存,解析它,然后如果它没有先用完内存,则返回结果.

    但是,在项目的 README 页面上,它们显示了您应该做些什么来避免这种情况:

    import com.monitorjbl.xlsx.StreamingReader;
    
    InputStream is = new FileInputStream(new File("/path/to/workbook.xlsx"));
    Workbook workbook = StreamingReader.builder()
        .rowCacheSize(100)    // number of rows to keep in memory (defaults to 10)
        .bufferSize(4096)     // buffer size to use when reading InputStream to file (defaults to 1024)
        .open(is);            // InputStream or File for XLSX file (required)
    

    之后,遍历工作簿,但不要使用 get(0) 方法,因为这似乎需要一次将所有工作簿加载到内存中。

    for (Sheet sheet : workbook){
        System.out.println(sheet.getSheetName());
        for (Row r : sheet) {
            for (Cell c : r) {
                System.out.println(c.getStringCellValue());
            }
        }
    }
    

    你试过吗?如果你这样做了,你应该提交一个错误,因为显然它不应该用尽所有可用内存,因为这是现有库的全部意义。

    【讨论】:

    • 您好 Renato - 我刚刚尝试了您的代码,它对我有用。我的问题解决了。你是对的 - 我正在将整个文件加载到内存中。使用缓存大小我能够解决这个问题。
    • @Bharat 该代码与我在同一时间发布,并且来自自述文件。此外,该用户是新用户,我提供了更多信息,说明为什么事情对他不利。
    • 我解释了他使用库的方式如何触发它立即将数据加载到内存中,他似乎没有意识到这一点。此外,其他答案还不够:您必须通过迭代器进行迭代,如上所示。像用户一样使用 get(0) 仍然会将所有数据加载到内存中。请善待并删除反对票。
    【解决方案3】:

    用easypoi做

    try {
            FileOutputStream fos    = new FileOutputStream("D:/home/excel/ExcelToCsv.test.csv");
            ImportParams     params = new ImportParams();
            params.setTitleRows(1);
            CsvExportParams csvExportParams = new CsvExportParams();
            IWriter ce = CsvExportUtil.exportCsv(csvExportParams, MsgClient.class, fos);
            ExcelImportUtil.importExcelBySax(
                    new FileInputStream(
                            new File(FileUtilTest.getWebRootPath("import/BigDataExport.xlsx"))),
                    MsgClient.class, params, new IReadHandler<MsgClient>() {
    
                        private List<MsgClient> list = new ArrayList<>();
    
                        @Override
                        public void handler(MsgClient o) {
                            list.add(o);
                            if (list.size() == 10000) {
                                ce.write(list);
                                list.clear();
                            }
                        }
    
                        @Override
                        public void doAfterAll() {
                            System.out.println("succcess--------------------------------");
                        }
                    });
        } catch (Exception e) {
    
        }
    

    地址https://github.com/jueyue/easypoi

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      相关资源
      最近更新 更多