JAVA Apache POI и большой набор результатов от DB2 вызывают исключение

Я пытаюсь создать из набора результатов файл 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();
}
}

Я был бы очень признателен, если бы кто-нибудь мог помочь.

заранее спасибо

Какая строка вызывает исключение? Что мне кажется странным: почему workbook.dispose () и где вы закрываете?

Ralf Renz 31.10.2018 10:53

Доказали ли вы, что XLSX может содержать все строки, если вы не используете Apache POI? Другими словами, сузьте область, где возникает проблема (например, в куче java, или в библиотеке Apache POI, или в вашем коде и т. д.). В частности, проверьте, можете ли вы создать xlsx вручную из Excel, импортировав файл с разделителями, созданный путем экспорта всех строк с помощью команды Db2 CLP export.

mao 31.10.2018 13:20

@ Ralf - строка, которая вызывает исключение, называется "workbook.write (out);". "Workbook.dispose ()" предназначен для удаления временных файлов из потока.

Matthew 31.10.2018 14:56

@mao - я могу без проблем создать полный экстракт в формате csv, а затем импортировать его в Excel и сохранить. Странно то, что я не получаю исключения с меньшим количеством строк например 15 000 строк, тогда файл записывается без проблем.

Matthew 31.10.2018 14:58

Найдите количество строк, вызывающих исключение, затем отладьте код в workbook.write (). Если у вас есть воспроизводимый тестовый пример, вы также можете открыть билет в библиотеке Apache-POI. Вы также должны исследовать, влияет ли увеличение кучи java.

mao 31.10.2018 15:07

Может быть связано с 64-битной ошибкой: bz.apache.org/bugzilla/show_bug.cgi?id=62872

blacelle 26.03.2021 22:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
926
0

Другие вопросы по теме