Я пытаюсь создать из набора результатов файл XLSX с Apache POI. Данные поступают из локального экземпляра DB2. В запрашиваемой мной таблице 580 000 записей.
Все идет хорошо, если я запрашиваю, например, первые 15 тыс. Строк, но когда я пытаюсь запросить все строки, я получаю следующее исключение, и файл поврежден, когда я пытаюсь открыть его в Excel.
Я использую Apache POI 4.0.0 и Java 1.8
Exception in thread "main" java.io.IOException: This archive contains unclosed entries.
at org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.finish(ZipArchiveOutputStream.java:467)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.injectData(SXSSFWorkbook.java:406)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:936)
at exportexcel.ExportExcel.createXLSX(ExportExcel.java:110)
at exportexcel.ExportExcel.main(ExportExcel.java:137)
C:\Users\USER\AppData\Local\NetBeans\Cache\9.0\executor-snippets\run.xml:111: The following error occurred while executing this line:
C:\Users\USER\AppData\Local\NetBeans\Cache\9.0\executor-snippets\run.xml:94: Java returned: 1
BUILD FAILED (total time: 12 minutes 19 seconds)
Строка, на которую указывает исключение, - это workbook.write(out);
.
Ниже моего кода я использую
package exportexcel;
import java.io.File;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
public class ExportExcel {
private static final String FILE_NAME = "c://file.xlsx";
public static void createXLSX() throws FileNotFoundException, IOException
{
SXSSFWorkbook workbook = new SXSSFWorkbook(100);
workbook.setCompressTempFiles(true);
SXSSFSheet sheet = workbook.createSheet("RawData");
String url = "jdbc:db2://localhost:50000/local";
java.util.Properties properties = new java.util.Properties();
properties.put("user", "user");
properties.put("password", "pass");
Connection con;
Statement stmt = null;
ResultSet rs;
try {
// Load the driver
Class.forName("com.ibm.db2.jcc.DB2Driver");
System.out.println("**** Loaded the JDBC driver\n");
// Create the connection using the IBM Data Server Driver for JDBC and SQLJ
con = DriverManager.getConnection (url, properties);
// Commit changes manually
con.setAutoCommit(false);
System.out.println("**** Created a JDBC connection to the data source\n");
stmt = con.createStatement();
rs = stmt.executeQuery("SELECT STATEMENT");
System.out.println("**** Created JDBC ResultSet object\n\n");
ResultSetMetaData rsMetaData = rs.getMetaData();
int numberOfColumns = rsMetaData.getColumnCount();
SXSSFRow row = sheet.createRow(0);
SXSSFCell cell;
for (int i = 1; i <= numberOfColumns; i++)
{
cell = row.createCell(i-1);
cell.setCellValue(rsMetaData.getColumnName(i));
}
int i = 1;
while (rs.next()) {
row = sheet.createRow(i);
for (int j = 1; j <= numberOfColumns; j++)
{
cell = row.createCell(j-1);
cell.setCellValue(rs.getString(j));
}
i++;
System.out.println(i);
} // Execute a query and generate a ResultSet instance
System.out.println("\n**** Fetched all rows from JDBC ResultSet\n");
// Close the ResultSet
rs.close();
System.out.println("**** Closed JDBC ResultSet\n");
// Close the Statement
stmt.close();
System.out.println("**** Closed JDBC Statement\n");
// Connection must be on a unit-of-work boundary to allow close
con.commit();
System.out.println("**** Transaction committed\n");
// Close the connection
con.close();
System.out.println("**** Disconnected from data source\n");
try (FileOutputStream out = new FileOutputStream(new File(FILE_NAME))) {
workbook.write(out);
workbook.dispose();
workbook.close();
out.flush();
}
System.out.println("File written!");
}
catch (ClassNotFoundException e)
{
System.err.println("Could not load JDBC driver");
System.out.println("Exception: " + e);
}
catch(SQLException ex)
{
System.err.println("SQLException information");
while(ex!=null) {
System.err.println ("Error msg: " + ex.getMessage());
System.err.println ("SQLSTATE: " + ex.getSQLState());
System.err.println ("Error code: " + ex.getErrorCode());
ex = ex.getNextException(); // For drivers that support chained exceptions
}
}
}
public static void main(String[] args) throws IOException {
createXLSX();
}
}
Я был бы очень признателен, если бы кто-нибудь мог помочь.
заранее спасибо
Доказали ли вы, что XLSX может содержать все строки, если вы не используете Apache POI? Другими словами, сузьте область, где возникает проблема (например, в куче java, или в библиотеке Apache POI, или в вашем коде и т. д.). В частности, проверьте, можете ли вы создать xlsx вручную из Excel, импортировав файл с разделителями, созданный путем экспорта всех строк с помощью команды Db2 CLP export.
@ Ralf - строка, которая вызывает исключение, называется "workbook.write (out);". "Workbook.dispose ()" предназначен для удаления временных файлов из потока.
@mao - я могу без проблем создать полный экстракт в формате csv, а затем импортировать его в Excel и сохранить. Странно то, что я не получаю исключения с меньшим количеством строк например 15 000 строк, тогда файл записывается без проблем.
Найдите количество строк, вызывающих исключение, затем отладьте код в workbook.write (). Если у вас есть воспроизводимый тестовый пример, вы также можете открыть билет в библиотеке Apache-POI. Вы также должны исследовать, влияет ли увеличение кучи java.
Может быть связано с 64-битной ошибкой: bz.apache.org/bugzilla/show_bug.cgi?id=62872
Какая строка вызывает исключение? Что мне кажется странным: почему workbook.dispose () и где вы закрываете?