如何在java中通过Apache POI Excel输出大型csv文件?

如何在java中通过Apache POI Excel输出大型csv文件?,java,excel,apache-poi,Java,Excel,Apache Poi,难以通过ApachePOIJava将300k行写入csv文件。我一直在尝试从一个包含300k行的excel文件生成一个csv文件。每次,当GCOutMemory试图写入输出csv文件时,都会出现错误。我甚至尝试过每10万行拆分一次写入。输出文件大小一直在增长,但我看不到system.println语句没有打印出来 import javafx.beans.binding.StringBinding; import org.apache.poi.hssf.record.crypto.Biff8Enc

难以通过ApachePOIJava将300k行写入csv文件。我一直在尝试从一个包含300k行的excel文件生成一个csv文件。每次,当GCOutMemory试图写入输出csv文件时,都会出现错误。我甚至尝试过每10万行拆分一次写入。输出文件大小一直在增长,但我看不到system.println语句没有打印出来

import javafx.beans.binding.StringBinding;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReadWrite {
    private static Logger logger= LoggerFactory.getLogger(ReadWrite.class);

    public static void main(String[] args) {
        try {
            long startReading = System.currentTimeMillis();
            Path path = Paths.get("/Users/venkatesh/Documents/Citiout_files/citiout300k_2sheets.xlsx");

            byte[] result = new byte[0];
            try {
                result = Files.readAllBytes(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            InputStream is = new ByteArrayInputStream(result);

            Workbook workbook = WorkbookFactory.create(is);

            long readDone = System.currentTimeMillis() - startReading;
            logger.info("read time " + readDone);



            Sheet sheet = workbook.getSheetAt(1);
            Row firstRow = sheet.getRow(0);
            int headcol = firstRow.getLastCellNum();
            long startTransform = System.currentTimeMillis();
            firstRow.createCell(headcol++).setCellValue("Sold Amount1");
            firstRow.createCell(headcol++).setCellValue("CF_Quantity1");
            firstRow.createCell(headcol++).setCellValue("CF_Quantity2");
            firstRow.createCell(headcol++).setCellValue("CF_TradePrice");
            firstRow.createCell(headcol++).setCellValue("CF_ForwardPrice");
            firstRow.createCell(headcol++).setCellValue("CF_UnrealizedPL");
            firstRow.createCell(headcol++).setCellValue("CF_Quantity1Round");
            firstRow.createCell(headcol++).setCellValue("CF_Quantity2Round");
            firstRow.createCell(headcol++).setCellValue("CF_FXLotKeyNoTradeDate");
            firstRow.createCell(headcol++).setCellValue("CF_FXRoundedKeyNoTradeDate");
            firstRow.createCell(headcol++).setCellValue("CF_SettlementDate");
            for (int i = 1; i <=sheet.getLastRowNum()+1; i++) {
                String jj="";
                Row nRow = sheet.getRow(i-1);
                for(Cell c:nRow) {
                    if (c.getColumnIndex()==3 && i!=1) {
                        Calendar cal = Calendar.getInstance();
                        Date date1 = new SimpleDateFormat("dd-MMM-yyyy").parse(c.getStringCellValue());
                        cal.setTime(date1);
                        jj = String.valueOf(cal.get(Calendar.MONTH)+1) + "/" + String.valueOf(cal.get(Calendar.DAY_OF_MONTH)) + "/" + String.valueOf(cal.get(Calendar.YEAR));
                    }
                }
                int count = nRow.getLastCellNum();
                //System.out.println(nRow.getCell(3).getClass());
                nRow.createCell(count++).setCellFormula("G" + i + "*-1");
                nRow.createCell(count++).setCellFormula("E" + i + "/" + "G" + i);
                nRow.createCell(count++).setCellFormula("G" + i + "/E" + i);
                nRow.createCell(count++).setCellFormula("ROUND(ABS(T" + i + "/S" + i + "),6)");
                nRow.createCell(count++).setCellFormula("ROUND(K" + i + ",6)");
                nRow.createCell(count++).setCellFormula("ROUND(N" + i + ",2)");
                nRow.createCell(count++).setCellFormula("ROUND(S" + i + ",0)");
                nRow.createCell(count++).setCellFormula("ROUND(T" + i + ",0)");
                nRow.createCell(count++).setCellFormula("CONCATENATE(T" + i + "," + "\"~\"" + ",S" + i + ")");
                nRow.createCell(count++).setCellFormula("CONCATENATE(X" + i + "," + "\"~\"" + ",Y" + i + ")");
                nRow.createCell(count++).setCellValue(jj);
                c.setCellValue(DateUtil.getExcelDate(calendar.getTime()));

            }
            long endTransform = System.currentTimeMillis() - startTransform;
            System.out.println("Transformations time " + endTransform);
            final FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
            FileWriter writer= new FileWriter(new enter code hereFile("/Users/venkatesh/Documents/cit300k.csv"));
            StringBuilder data = new StringBuilder();
            Iterator<Row> rowIterator = workbook.getSheetAt(1).iterator();

            try {
                while (rowIterator.hasNext()) {

                    Row row = rowIterator.next();


                    Iterator<Cell> cellIterator = row.cellIterator();
                    while (cellIterator.hasNext()) {
                        Cell cell = cellIterator.next();

                        CellType type = cell.getCellType();
                        if (type == CellType.BOOLEAN) {
                            data.append(cell.getBooleanCellValue());
                        } else if (type == CellType.NUMERIC) {
                            data.append(cell.getNumericCellValue());

                        } else if (type == CellType.STRING) {
                            data.append(cell.getStringCellValue());
                        } else if (type == CellType.FORMULA) {
                            switch (evaluator.evaluateFormulaCell(cell)) {
                                case STRING:
                                    data.append(cell.getStringCellValue());
                                    break;
                                case NUMERIC:
                                    data.append(cell.getNumericCellValue());
                                    break;
                            }
                        } else if (type == CellType.BLANK) {
                        } else {
                            data.append(cell + "");
                        }
                        data.append(",");
                    }
                    writer.append(data.toString());
                    writer.append('\n');
                }
            } catch(Exception e){
                e.printStackTrace();
            }
            finally{
                if(writer!=null){
                    writer.flush();
                    writer.close();
                }
            }

            for (MemoryPoolMXBean mpBean: ManagementFactory.getMemoryPoolMXBeans()) {
                if (mpBean.getType() == MemoryType.HEAP) {
                    System.out.printf(
                            "Name: %s: %s\n",
                            mpBean.getName(), mpBean.getUsage()
                    );
                }
            }
            try {
                workbook.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
}


20-01-12 19:52:49:267  INFO main ReadWrite:64 - read time 11354
Transformations time 38659
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.util.TreeMap$Values.iterator(TreeMap.java:1031)
    at org.apache.poi.xssf.usermodel.XSSFRow.cellIterator(XSSFRow.java:117)
    at org.apache.poi.xssf.usermodel.XSSFRow.iterator(XSSFRow.java:132)
    at org.apache.poi.xssf.usermodel.XSSFEvaluationSheet.getCell(XSSFEvaluationSheet.java:86)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:402)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:275)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:216)
    at org.apache.poi.xssf.usermodel.BaseXSSFFormulaEvaluator.evaluateFormulaCellValue(BaseXSSFFormulaEvaluator.java:56)
    at org.apache.poi.ss.formula.BaseFormulaEvaluator.evaluateFormulaCell(BaseFormulaEvaluator.java:185)
    at ReadWrite.main(ReadWrite.java:150)

导入javafx.beans.binding.StringBinding;
导入org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
导入org.apache.poi.hssf.usermodel.HSSFDateUtil;
导入org.apache.poi.hssf.usermodel.HSSFWorkbook;
导入org.apache.poi.poifs.filesystem.poifsfsystem;
导入org.apache.poi.ss.usermodel.*;
导入org.apache.poi.ss.util.CellReference;
导入org.apache.poi.xssf.streaming.SXSSFWorkbook;
导入org.apache.poi.xssf.usermodel.xssf工作簿;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入java.io.*;
导入java.lang.management.ManagementFactory;
导入java.lang.management.MemoryPoolMXBean;
导入java.lang.management.MemoryType;
导入java.math.BigDecimal;
导入java.nio.ByteBuffer;
导入java.nio.channels.FileChannel;
导入java.nio.charset.charset;
导入java.nio.file.Files;
导入java.nio.file.Path;
导入java.nio.file.path;
导入java.sql.Timestamp;
导入java.text.DateFormat;
导入java.text.simpleDataFormat;
导入java.util.*;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.regex.Matcher;
导入java.util.regex.Pattern;
公共类读写{
私有静态记录器Logger=LoggerFactory.getLogger(ReadWrite.class);
公共静态void main(字符串[]args){
试一试{
长启动时间=System.currentTimeMillis();
Path Path=Path.get(“/Users/venkatesh/Documents/Citiout_files/citiout300k_2sheets.xlsx”);
字节[]结果=新字节[0];
试一试{
结果=Files.readAllBytes(路径);
}捕获(IOE异常){
e、 printStackTrace();
}
InputStream is=新的ByteArrayInputStream(结果);
工作簿=WorkbookFactory.create(is);
long readDone=System.currentTimeMillis()-startReading;
logger.info(“读取时间”+读取完成);
工作表=工作簿。getSheetAt(1);
Row firstRow=sheet.getRow(0);
int headcol=firstRow.getLastCellNum();
long startTransform=System.currentTimeMillis();
firstRow.createCell(headcol++).setCellValue(“售出金额1”);
firstRow.createCell(headcol++).setCellValue(“CF_Quantity1”);
firstRow.createCell(headcol++).setCellValue(“CF_Quantity2”);
firstRow.createCell(headcol++).setCellValue(“CF_TradePrice”);
firstRow.createCell(headcol++).setCellValue(“CF_ForwardPrice”);
firstRow.createCell(headcol++).setCellValue(“CF_UnrealizedPL”);
firstRow.createCell(headcol++).setCellValue(“CF_Quantity1Round”);
firstRow.createCell(headcol++).setCellValue(“CF_Quantity2Round”);
firstRow.createCell(headcol++).setCellValue(“CF_FXLotKeyNoTradeDate”);
firstRow.createCell(headcol++).setCellValue(“CF_FXRoundedKeyNoTradeDate”);
firstRow.createCell(headcol++).setCellValue(“CF_结算日期”);

对于(int i=1;i,现在我们有了一个可用的stacktrace,很明显,这个问题在编写CSV文件时并没有发生。它实际上是在您计算电子表格公式时发生的。我猜公式是在一张工作表中所有行的总和……或者类似的东西

这是一个问题,可能没有简单的解决方案

下面是报告的内容:

文件大小/内存使用

  • Excel文件格式有一些固有的限制。这些限制是在类中定义的。只要您有足够的 在主内存中,您应该能够处理达到这些限制的文件。 对于使用默认POI类的大型文件,您可能需要 非常大的内存量。
    • 如果需要,有几种方法可以克服主内存限制:
    • 对于写入非常大的文件,有一个允许将数据流式写入文件(具有特定的 对您可以执行的操作的限制,因为只有部分文件保存在 内存)
    • 对于读取非常大的文件,请查看示例,该示例显示了如何在流媒体中读取文件 时尚(同样对你能阅读的信息有一些限制 文件之外,但如果 (必要的)
很明显,您遇到了这些内存限制。基本上,POI试图将太多的电子表格加载到内存中…而您正在评估电子表格公式…并且正在填充堆

一个解决方案是增加Java堆的大小。或者,如果你已经在堆中使用了所有可用的RAM,那么在一台RAM更多的机器上运行转换。现在很多标准PC都有16GB的RAM。也许是时候进行硬件升级了?但我猜你已经想到了这一点

如果增加堆大小不可行,则需要重写应用程序以使用
SXSSFWorkbook
。此外,您可能需要将使用公式求值的方法替换为使用本机Java以与电子表格逐行流式处理兼容的方式进行计算。(这将取决于公式的作用。)


查看POI文档中的链接示例以了解想法。

请向我们展示OutOfMemoryError的完整堆栈跟踪。如果您想编写CSV文件,为什么不将其作为CSV文件编写?如果您实际上不需要完整的XLS电子表格,为什么要使用Apache POI?@StephenC我已附上错误堆栈跟踪。请查看并删除我不知道