2009-09-28 52 views
16

我正在尋找使用Java以編程方式寫入excel(.xls MS Excel 2003格式)文件。 excel輸出文件可能包含〜200,000行,我打算將其分割成多個頁面(每頁64k行,由於excel的限制)。使用java編寫巨大的excel文件的API

我嘗試過使用apache POI API,但它似乎是由於API對象模型而導致的內存豬。我不得不將單元格/工作表添加到內存中的工作簿對象,並且只有在添加完所有數據後,纔可以將工作簿寫入文件!這裏的Apache如何建議的樣品我寫使用他們的API Excel文件:

Workbook wb = new HSSFWorkbook(); 
Sheet sheet = wb.createSheet("new sheet"); 

//Create a row and put some cells in it 
Row row = sheet.createRow((short)0); 

// Create a cell and put a value in it. 
Cell cell = row.createCell(0); 
cell.setCellValue(1); 

// Write the output to a file 
FileOutputStream fileOut = new FileOutputStream("workbook.xls"); 
wb.write(fileOut); 
fileOut.close(); 

顯然,寫作〜20K行(每行10-20一些列)給了我可怕的「的java.lang。 OutOfMemoryError:Java堆空間「。

我已經嘗試使用Xms和Xmx參數Xms512m和Xmx1024增加JVM初始堆和最大堆大小。仍然不能將超過150k行寫入文件。

我正在尋找一種方法將流寫入excel文件,而不是在將內容寫入磁盤之前在內存中構建整個文件,這將有望節省大量內存使用量。任何替代API或解決方案將不勝感激,但我只限於使用Java。謝謝! :)

+0

你可以看看:http://stackoverflow.com/questions/6004379/java-write-excel-files-with-poi-event-model – ParagJ

+0

只有1024m?嘗試4086(4演出)。有時我們會在工作中運行8個gms vms)。電子表格是這樣設計的,甚至可以同時在電子表格的一部分上工作? –

回答

6

所有現有的Java API都嘗試在RAM中一次構建整個文檔。嘗試編寫符合新的xslx文件格式的XML文件。爲了讓你開始,我建議在Excel中以所需的格式構建一個小文件並保存。然後打開它並檢查結構並更換你想要的零件。

維基百科有一個good article about the overall format

+0

Thanks!I沒有想到xslx,但客戶端使用office 2003和xslx變得有問題,他們也不能安裝MS插件來將xslx轉換爲xls。兩個詞 - 「企業IT」:| – Jaskirat

+0

創建文件,在Excel中打開並保存以舊格式生成報告 –

+0

報告將每天/每週生成,在excel中打開並以舊格式保存並不是真的可行 – Jaskirat

0

當您將數據插入單元格或執行數據計算/生成時,是否發生此內存問題?

如果您打算將文件加載到由預定義的靜態模板格式組成的Excel中,那麼最好保存一個模板並多次重複使用。通常情況下,當您要生成日常銷售報告等時發生模板案例...

否則,您每次需要從頭開始創建新的行,邊界,列等。

到目前爲止,Apache POI是我發現的唯一選擇。

「顯然,寫〜20k行(每行有10-20列)給了我可怕的」java.lang.OutOfMemoryError:Java堆空間「。

「企業IT」

你可以做的是 - 執行批量數據插入。創建一個queuetask表,每次生成1頁後,休息幾秒鐘,然後繼續第二部分。如果您擔心隊列任務期間的動態數據更改,可以先將主鍵放入Excel中(通過隱藏和鎖定用戶視圖中的列)。第一次運行將插入主鍵,然後第二個隊列向前運行將從記事本中讀出並逐個執行任務。

+0

我們爲什麼要討論任務隊列? :-S 我真的不明白你想說什麼。當你說使用模板時,你想讓我使用jxls api還是類似的東西? – Jaskirat

2

還有JExcelApi,但它使用更多的內存。我認爲你應該創建.csv文件並在Excel中打開它。它可以讓你傳遞大量數據,但是你不會做任何「超級魔術」。

+0

分隔文件當然非常輕便!但不幸的是,這不是一個選項。沒有超凡的魔法和沒有數據格式等我需要寫.xls文件。 :( – Jaskirat

+1

我認爲你應該試着說服你的老闆使用.csv,因爲以後你會遇到很多緩慢工作的問題,整個webapp都無法工作,因爲有10個人正在生成excel報告。 – IAdapter

0

我們做了一些非常相似,數據量相同的數據,我們不得不切換到JExcelapi,因爲POI對資源來說太重了。試試JexcelApi,當你不得不操縱大的Excel文件時,你不會後悔!

+0

謝謝,我會用JExcelAPI做一個概念驗證,看看它是如何針對POI的。但結構看起來很相似,所以我真的不知道它會產生多大的差異。你可以給我一些比例,如果可能的話,數字? – Jaskirat

+0

由於我們在一段時間之前就拋棄了基於POI的代碼,因爲與您的代碼完全相同的問題,抱歉,我不能。不過,我只是看了Glassfish服務器,其他應用程序託管生成.xls文件的應用程序。它有-Xmx768m,我們從來沒有導致Excel錯誤的Excel世代。我只生成了10 xls的45000行* 8列,堆上有574,423,040字節。希望這會有所幫助 – fvu

+0

多個xls不會是一個問題,因爲一旦它們被刷新到文件,該對象可能被髮送垃圾回收。所以是一個45k行×8列的excel文件將運行在768Mb以下,但是150,000 x 20列需要超過1GB,並且我不能按指數規律分配內存,這會拼寫錯誤的設計。 :D無論如何感謝所有這一切! :) – Jaskirat

3

查看繭形項目中的HSSF serializer

The HSSF serializer catches SAX events and creates a spreadsheet in the XLS format used by Microsoft Excel

1

考慮使用CSV格式。這樣你就不再受到內存的限制 - 也許只有在爲CSV預填充數據的時候,也可以高效地完成這項工作,例如使用例如LIMIT/OFFSET查詢DB的行子集並立即將其寫入文件而不是在編寫任何行之前將整個數據庫表內容拖入Java的內存中。一張「表」中的行數的Excel限制將增加到大約一百萬。這就是說,如果數據實際上來自數據庫,那麼我會高度重新考慮Java是否是適合這種情況的正確工具。大多數體面的數據庫都有一個導出到CSV的功能,可以毫無疑問更有效地完成這項任務。例如,MySQL可以使用LOAD DATA INFILE命令。

4

爲了克服堆空間異常,我不得不將我的文件分成幾個excel文件。我認爲大約5行22列是關於它的,所以我只是製作了我的邏輯,以便每隔5K行我會結束文件,開始一個新文件,並相應地對這些文件進行編碼。

在我有20k +行寫入的情況下,我會有4個以上不同的文件來表示數據。

+0

是的,我也有這個想法,多個Excel文件,然後可能將其壓縮到一個存檔。但這還不夠好。無論如何謝謝你的建議。 – Jaskirat

+0

如果你想出一個解決方案,我appriciate如果你更新你的問題=)這是一個非常惱人的問題。 –

+0

現在我面臨同樣的問題。正在計劃分割數據。但我可以知道你是如何做到這一點? –

9

嘗試使用SXSSF工作簿,對巨大的XLS文件這就是偉大的事情,它的構建文件,並在所有不吃RAM,使用becase的NIO

+0

SXSSF不支持使用XLS https://stackoverflow.com/questions/20678164/saving-sxssf-as-xls-file –

1

我們開發了一個Java庫,用於此目的,目前它是可用作爲開源項目https://github.com/jbaliuka/x4j-analytic。我們將其用於運營報告。 我們生成巨大的Excel文件,〜200,000應該沒有問題,Excel也設法打開這樣的文件。 我們的代碼使用POI來加載模板,但生成的內容直接流式傳輸到內存中沒有XML或對象模型層的文件。