如何在java中通过Apache POI Excel输出大型csv文件?
难以通过ApachePOIJava将300k行写入csv文件。我一直在尝试从一个包含300k行的excel文件生成一个csv文件。每次,当GCOutMemory试图写入输出csv文件时,都会出现错误。我甚至尝试过每10万行拆分一次写入。输出文件大小一直在增长,但我看不到system.println语句没有打印出来如何在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
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我已附上错误堆栈跟踪。请查看并删除我不知道