简体   繁体   English

使用java.util.zip。*解压缩使用Apache POI创建的xlsx blob时失败

[英]Failure when using java.util.zip.* to unzip an xlsx blob created with Apache POI

The following code is a test program that creates an xlsx blob using Apache POI and unzips the blob (xlsx is in zip format) to check some values. 以下代码是一个测试程序,它使用Apache POI创建xlsx blob并解压缩blob(xlsx是zip格式)以检查某些值。 The code is based on Stack Overflow questions but I have not been able to get unzipping to work properly. 该代码基于Stack Overflow问题,但我无法解压缩才能正常工作。 A requirement for this is that the filesystem must not be touched so we resort to streams. 对此的要求是不得触及文件系统,因此我们求助于流。

The problem is that the line 问题是这条线

int size = (int) entry.getSize();

always produces -1. 总是产生-1。 However, see the comments before 但是,请参阅之前的评论

zipInput.closeEntry();

for a variation that gets further into the program but seems incorrect. 对于进一步进入程序但看起来不正确的变体。

We don't want to use POI itself for reading the xlsx file because we are testing a problem where POI appears to not be cooperating with Apache Struts and we want to eliminate the case where the way we are using POI independent of Struts is the culprit. 我们不想使用POI本身来读取xlsx文件,因为我们正在测试POI似乎与Apache Struts没有合作的问题,我们想要消除我们使用独立于Struts的POI的方式是罪魁祸首的情况。 Once this test passes, if the problem Struts reports remains, we know to look at Struts itself rather than the way we are using POI. 一旦这个测试通过,如果问题Struts报告仍然存在,我们知道看看Struts本身而不是我们使用POI的方式。

/**
 * Short, Self Contained, Correct Example of
 * 1) creating an xlsx blob with test data;
 * 2) sending it to a stream;
 * 3) unzipping the xlsx;
 * 4) checking the worksheet's xml file for
 * correct test values.
 * Heavily inlined from two other properly factored
 * files, one POI wrapper and one JUnit test case
 * (although the test is not a "unit test" since it
 * only tests third party library integration)
 * DEPENDENCIES
 * 1) poi-3.8.jar
 * 2) poi-ooxml-3.8.jar
 * 3) xmlbeans-2.6.0.jar
 * 4) dom4j-1.6.1.jar
 * 5) poi-ooxml-schemas-3.8.jar
 * Other solutions attempted:
 * 1) commons-compress: always returned byte array of proper size
 * but containing all zeros.
 * Note that we do NOT want to use the filesystem. This exercise's
 * purpose is to create dynamically generated xlsx files delivered
 * via HTTP. The filesystem is never involved.
 */
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class CreateWorkbook
{
    public static void main(String[] args) throws IOException
    {
        // create the data to place into workbook
        List<List<String>> resultset = new ArrayList<List<String>>();
        List<String> row = new ArrayList<String>();
        row.add("A1");
        row.add("B1");
        row.add("C1");
        resultset.add(row);
        row = new ArrayList<String>();
        row.add("A2");
        row.add("B2");
        row.add("C2");
        resultset.add(row);
        row = new ArrayList<String>();
        row.add("A3");
        row.add("B3");
        row.add("C3");
        resultset.add(row);
        // create POI workbook and fill it with resultSet
        XSSFWorkbook workbook = new XSSFWorkbook();
        Sheet s = workbook.createSheet();
        for (int i = 0; i < resultset.size(); i++)
        {
            List<String> record = resultset.get(i);
            Row r = s.createRow(i);
            for (int j = 0; j < record.size(); j++)
                r.createCell(j).setCellValue(record.get(j));
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        workbook.write(out);
        out.flush();
        // retrieve workbook's data into a string and
        // test if the cell values (a1,b2,c3,etc) appear
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        // xlsx is a zipped archive so we need to unzip
        ZipInputStream zipInput = new ZipInputStream(in);
        assert zipInput.available() == 1;
        ZipEntry entry = zipInput.getNextEntry();
        assert entry != null;
        while (entry != null)
        {
            // since this "if" condition passes during execution we
            // know that the stream contains a zip archive with
            // an entry called "xl/worksheets/sheet1.xml". Therefore,
            // ZipEntry retrieval appears to work correctly and the
            // archive has at least a partially correct zip format.
            if (entry.getName().equals("xl/worksheets/sheet1.xml"))
            {
                int size = (int) entry.getSize();
                // ==============================================
                // always fails, reports -1
                assert size > 0 : size;
                // ==============================================
                byte[] bytes = new byte[size];
                int readbytes = zipInput.read(bytes, 0, size);
                assert readbytes > 0 : readbytes;
                // nothing after this line has been tested
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < size; i++)
                    builder.append(Character.toString((char) bytes[i]));
                String xml = builder.toString();
                assert xml.contains("A1");
                assert xml.contains("B2");
                assert xml.contains("C3");
                break;
            }
            // Swapping the order of these two lines actually
            // causes the program to go further, with size = 678
            // and failing at the readbytes assertion rather than
            // the size assertion.
            // I thought swapping would mess everything up since
            // the entry would be closed immediately after obtaining
            // it.
            zipInput.closeEntry();
            entry = zipInput.getNextEntry();
        }
        zipInput.close();
        in.close();
    }
}

You not exactly rigth work with Zip. 你并不完全适合使用Zip。

Try this snippet: 试试这个片段:

        if (entry.getName().equals("xl/worksheets/sheet1.xml"))
        {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            IOUtils.copy(zipInput, bos);
            String xml = bos.toString();
            assert xml.contains("A1");
            assert xml.contains("B2");
            assert xml.contains("C3");
            break;
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM