2016-01-25 52 views
-1

我試圖使用從數據庫中獲取的數據創建多個Excel工作表。每張Excel表格包含60多列和大約50k條記錄(可能有所不同)。問題在於系統花了很多時間(5分鐘以上),然後以java.lang.OutOfMemoryError: GC overhead limit exceeded異常結束。使用Apache POI寫入60列以上的大型Excel工作表

我試着將列數減少到只有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問題,但無法找出有用的東西。想知道我是否應該嘗試解決這個問題。

+1

是否有明確的需求將輸出寫入Excel文件?如果沒有,那麼你可以嘗試寫入一個更快的CSV文件。您也可以爲此使用OpenCSV或FasterXML。如果沒有,那麼你可能會嘗試一次寫入1000個記錄的批處理文件,而不是一次寫入所有內容。 – user2004685

+0

這個問題仍然是開放的,或者我的答案解決了你的問題?如果是這樣,請關閉該問題。 thx – Rainer

回答

3

沒有進一步的信息,我只能猜測你是真正的問題。但我可以告訴你,apache poi可以創建超過1000列的excel表格,並且有超過20,000行的顏色,樣式和內容(已經完成)。

確保你使用的apache.poi API

org.apache.poi.xssf.streaming

這裏的流API是阿帕奇

Big Grid Demo

UPDATE

的演示由於它規定在演示中,我鏈接了t啊,你也許應該使用新的SXSSF用戶模型(我用的,如果我記得正確的),因爲它HANDELS所有的流媒體的東西給你;-)

SXSSF (Streaming Usermodel API)

1

這似乎有點倒退,但我更喜歡在使用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; 
} 
} 
+0

你爲什麼喜歡那個?有什麼理由呢?一旦微軟開始更改模式文件,它會變得更加複雜並且會導致不兼容的文件。 – Rainer

+0

如果Microsoft更新文件結構,那麼與升級POI並重新測試所有內容沒有任何區別。 POI是一個很好的工具,但對於我的大數據集味道總是會有點慢。 xlsx文件的XML並不是那麼複雜,所以我更願意手動構建它們以更好地控制瓶頸。對於更小或更復雜的電子表格,我仍然會使用API​​。 – LAROmega

+0

我的評論與此處的行有關 xmlns:r = \「http://schemas.openxmlformats.org/officeDocument/2006/relationships \」 – Rainer