[英]Writing a large Excel sheet with 60+ columns using Apache POI
我正在嘗試使用從數據庫中獲取的數據創建多個Excel工作表。 每個Excel工作表包含60多個列和大約5萬條記錄(可能有所不同)。 問題是系統花費大量時間(5分鍾以上),然后最終出現java.lang.OutOfMemoryError: GC overhead limit exceeded
異常。
我嘗試將列數減少到僅6,這樣就大大縮短了周轉時間。
這是生成Excel工作表的字節數組的代碼:
int rowIndex = 0;
while (iterator.hasNext()) {
List<CustomCellDataBean> cellData = iterator.next();
// Insert generic data
Row dataContentRow = sheet.createRow((short) rowIndex);
for (int counter = 0; counter < cellData.size(); counter++) {
CustomCellDataBean cd = cellData.get(counter);
if (cd.getValue() != null) {
// switch case based on the datatype of the cell
switch (cd.getType()) {
}
}
}
rowIndex++;
}
// write to ByteArrayOutputStream and return the array of bytes
已經提到了幾個SO問題,但無法找出有用的東西。 想知道是否應該嘗試解決該問題。
沒有更多信息,我只能猜測您的真正問題是什么。 但是我可以告訴你,apache poi可以創建具有1000列以上和2萬行以上的顏色,樣式和內容的Excel工作表(已經完成)。
org.apache.poi.xssf.streaming
這是Apache的演示
更新
正如它在演示中所指出的那樣,我鏈接到您的用戶可能應該使用新的SXSSF用戶模型(如果我記得正確的話,我會使用該模型),因為它可以為您處理所有流式傳輸內容;-)
似乎有些倒退,但是當使用帶有POI的大型數據集時,我更喜歡手動構建工作表。 這是我使用的幫助程序類,可幫助您入門:
public class Worksheet {
private static Logger logger = Logger.getLogger(Worksheet.class);
/**
* XML data for building the worksheet.
*/
public StringBuilder data = new StringBuilder();
/**
* The name of this worksheet's entry in the XLSX file.
*/
public String zipEntryName;
/**
* Tracks the last row written to the spreadsheet.
*/
// xslx rows start at 1
// Changed lastRow to init at 0 after using startRow() for headers.
public int lastRow = 0;
/**
* Tracks the last cell written to the spreadsheet.
*/
public int lastCell = 0;
/**
* Stores any styles that have been generated using XSSF.
*/
public HashMap<String, XSSFCellStyle> styles = new HashMap<String, XSSFCellStyle>();
/**
* Tracks any merged cells so that they can be appended to the worksheet XML.
*/
public List<String> merged = new ArrayList<String>();
private boolean inRow = false;
private XSSFSheet myWorksheet = null;
public void setPOIWorksheet(XSSFSheet sheet){
myWorksheet = sheet;
this.zipEntryName = sheet.getPackagePart().getPartName().getName().substring(1);
}
public XSSFSheet getPOIWorksheet(){
return this.myWorksheet;
}
/**
* Write the raw XML data of newSheets to the existing XLSX file in workbook.
* @param workbook The current XSLX file to overwrite data in.
* @param newSheets A Collection of Worksheet objects containing the XML data to insert into workbook.
* @param newFile The OutputStream to write the new XLSX file to.
*/
public static void writeWorksheetsToWorkbook(InputStream workbook, Collection<Worksheet> newSheets, OutputStream newFile)
{
ZipOutputStream zipStream = null;
try{
zipStream = new ZipOutputStream(newFile);
ZipInputStream zip = new ZipInputStream(workbook);
ZipEntry entry;
// Copy unaffected entries.
while((entry = zip.getNextEntry()) != null){
boolean found = false;
for(Worksheet ws : newSheets){
if(entry.getName().equals(ws.zipEntryName)){
found = true;
break;
}
}
if(!found){
zipStream.putNextEntry(new ZipEntry(entry.getName()));
byte[] buffer = new byte[1];
while((zip.read(buffer, 0, 1)) > -1)
zipStream.write(buffer);
}
}
// Insert XML for entries being replaced.
for(Worksheet ws : newSheets){
zipStream.putNextEntry(new ZipEntry(ws.zipEntryName));
byte[] data = ws.data.toString().getBytes();
zipStream.write(data, 0, data.length);
}
}catch(Exception e){
logger.error("Error creating xlsx", e);
}finally{
if(zipStream != null) try{ zipStream.close(); }catch(Exception e){}
if(newFile != null) try{ newFile.close(); }catch(Exception e){}
}
}
/**
* Write the raw XML data of newSheets to the existing XLSX file in workbook.
* @param workbook The current XSLX file to overwrite data in.
* @param newSheets A Collection of Worksheet objects containing the XML data to insert into workbook.
* @param return A byte[] containing the new workbook.
*/
public static byte[] writeWorksheetsToWorkbook(InputStream workbook, Collection<Worksheet> newSheets){
ByteArrayOutputStream bout = new ByteArrayOutputStream();
writeWorksheetsToWorkbook(workbook, newSheets, bout);
return bout.toByteArray();
}
public Worksheet setWorksheetName(XSSFSheet xssfWS){
zipEntryName = xssfWS.getPackagePart().getPartName().getName().substring(1);
return this;
}
/**
* Write all of the XML used for starting the worksheet.
*/
public Worksheet startWorksheet(){
data.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
data.append("<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ");
data.append("xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" ");
data.append("xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" >\n");
data.append("<sheetData>\n");
return this;
}
/**
* Write the XML for closing the worksheet, including merged cell data.
*/
public Worksheet closeWorksheet(){
data.append("</sheetData>\n");
if(merged.size() > 0){
data.append("<mergeCells count=\"");
data.append(merged.size());
data.append("\">");
for(String cells : merged){
data.append("<mergeCell ref=\"");
data.append(cells);
data.append("\"/>");
}
data.append("</mergeCells>\n");
}
data.append("</worksheet>\n");
return this;
}
/**
* Method for adding a new row to an Excel file. This was added as part of Period Compliance Report because
* we're not iterating over data like previous reports.
*
* This will automatically close the previous row if left open.
*/
public Worksheet startRow(){
lastCell = 0;
if(inRow)
endRow();
lastRow++;
data.append("<row r=\""+lastRow+"\">");
inRow = true;
return this;
}
/**
* Method for closing a row in an Excel file.
*/
public Worksheet endRow(){
data.append("</row>\n");
inRow = false;
return this;
}
/**
* Method for adding Date data to an Excel file cell.
* @param value The data to be added to the cell.
*/
public Worksheet addDateCell(String value){
return addTextCell(value, null);
}
/**
* Method for adding Date data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting to be used.
*/
public Worksheet addDateCell(String value, String formatting){
return addTextCell(value, formatting);
}
/**
* Method for adding String data to an Excel file cell. This was added as part of Period Compliance Report because
* we're not iterating over data like previous reports.
* @param value The data to be added to the cell.
*/
public Worksheet addTextCell(String value){
return addTextCell(value, null);
}
/**
* Method for adding String data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
*/
public Worksheet addTextCell(String value, String formatting){
return addCell(StringEscapeUtils.escapeXml(value), formatting, false, 0);
}
/**
* Method for adding String data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
* @param mergeRight The number of cells to the right of this one that should be merged.
*/
public Worksheet addMergedTextCell(String value, String formatting, int mergeRight){
return addCell(StringEscapeUtils.escapeXml(value), formatting, false, mergeRight);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
*/
public Worksheet addNumberCell(String value){
return addNumberCell(value, null);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
*/
public Worksheet addNumberCell(Number value){
return addNumberCell(value.toString(), null);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
*/
public Worksheet addNumberCell(String value, String formatting){
return addCell(value, formatting, true, 0);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
*/
public Worksheet addNumberCell(Number value, String formatting){
return addCell(value.toString(), formatting, true, 0);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
* @param mergeRight The number of cells to the right of this one that should be merged.
*/
public Worksheet addMergedNumberCell(String value, String formatting, int mergeRight){
return addCell(value, formatting, true, mergeRight);
}
/**
* Method for adding numerical data to an Excel file cell.
* @param value The data to be added to the cell.
* @param formatting Any style formatting used on the cell.
* @param mergeRight The number of cells to the right of this one that should be merged.
*/
public Worksheet addMergedNumberCell(Number value, String formatting, int mergeRight){
return addCell(value.toString(), formatting, true, mergeRight);
}
/**
* Method for adding data to an Excel file cell.
* @param value The data to be added to the cell.
* @param element The cell location on the table row.
* @param formatting The formatting style to use.
* @param mergeRight The number of cells that should be merged to the right.
* @return This Worksheet.
*/
private Worksheet addCell(String value, String formatting, boolean number, int mergeRight){
String ref = addCell(value, formatting, number);
if(mergeRight > 0){
String right = null;
for(int i = 1; i <= mergeRight; i++)
right = addCell("", formatting, false);
merged.add(ref+":"+right);
}
return this;
}
/**
* Method for adding data to an Excel file cell.
* @param value The data to be added to the cell.
* @param element The cell location on the table row.
* @param formatting The formatting style to use.
* @return A String with the new cell's location.
*/
private String addCell(String value, String formatting, boolean number){
String ref = new CellReference(lastRow-1,lastCell).formatAsString();
data.append("<c ");
if(formatting != null && styles.containsKey(formatting)){
XSSFCellStyle style = styles.get(formatting);
data.append("s=\"");
data.append(style.getIndex());
data.append("\" ");
}else if(formatting != null)
logger.debug("could not find style "+formatting);
data.append("r=\"");
data.append(ref);
data.append((number) ? "\">" : "\" t=\"inlineStr\">");
/*if(formatting == null) data.append((number) ? "\">" : "\" t=\"inlineStr\">");
else{
data.append("\" t=\"");
data.append(formatting);
data.append("\">");
}*/
data.append((number) ? "<v>" : "<is><t>");
data.append(value);
data.append((number) ? "</v>" : "</t></is>");
data.append("</c>");
lastCell++;
return ref;
}
/**
* Adds a bunch of cells to a row quickly.
* @param fields The fields to be added.
*/
public Worksheet quickAdd(String... fields){
if(!inRow)
startRow();
for(int i = 0; i < fields.length; i++)
addTextCell(fields[i]);
return this;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.