从内存文件创建磁盘上的Zip文件

时间:2013-12-12 10:20:41

标签: java apache-poi zip4j

首先,请原谅我糟糕的编码!

要求:
1.从数据库ResultSet在内存中创建xls / xlsx报告(即,不应将纯文本文件写入磁盘)。
2.在磁盘上创建ZIP从内存中的xlsx文件。

环境:
WinXP SP2,JDK1.6_06,Zip4j1.3.1,poi3.8

我正在使用Apache的POI和Zip4j,并且正在关注在“http://www.lingala.net/zip4j/forum/index.php?topic=257.0”发表的Mr.Shrikant的例子

观察:
1.此程序将27,842字节的xlsx文件写入磁盘以获取样本数据 2.同一个工作簿创建ByteArrayOutputStream,baoStream的大小为49022bytes
3.加密和压缩后,它创建大小为43,084字节的文件 4.在提取Zip文件时,
a)WinZip,抛出错误“UnExpected End of File”
b)Winrar,抛出“CRC错误”

请在任何我错的地方纠正我,无论我在哪里,都要改善!

提前致谢!

package zipconversion;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
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.Statement;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import java.util.Random;
import net.lingala.zip4j.io.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ZipCreationInMemory {

    ZipOutputStream zos = null;
    XSSFWorkbook workbook = null;
    ByteArrayOutputStream baoStream = null;
    String path = null;
    String xlsxfileExtn = null;
    String zipfileExtn = null;
    String onlyFileName = null;
    String xlsxFileName = null;
    String zipFileName = null;
    String xlsxFilePath = null;
    String zipFilePath = null;

    public static int randInt(int min, int max) {
        Random rand = new Random();
        int randomNum = rand.nextInt((max - min) + 1) + min;
        return randomNum;
    }

    public void createXlsxFile() {
        try {
            SimpleDateFormat timeFormat = new SimpleDateFormat("hh_mm_ss");
            path = "D:\\abcd\\";
            xlsxfileExtn = ".xlsx";
            zipfileExtn = ".zip";
            onlyFileName = "ReportData_".concat(timeFormat.format(new Date()));
            xlsxFileName = onlyFileName + xlsxfileExtn;
            zipFileName = onlyFileName + zipfileExtn;
            xlsxFilePath = path + xlsxFileName;
            zipFilePath = path + zipFileName;
            FileOutputStream out = new FileOutputStream(new File(xlsxFilePath));
            workbook = new XSSFWorkbook();
            XSSFSheet sheet = workbook.createSheet("Report");
            XSSFRow rowHead = sheet.createRow((short) 0);

            XSSFCellStyle headStyle = workbook.createCellStyle();
            XSSFFont headerFont = workbook.createFont();
            headerFont.setBold(true);
            headerFont.setColor(new XSSFColor(new java.awt.Color(255, 0, 0)));
            headStyle.setFont(headerFont);
            headStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(255, 255, 255)));
            headStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

            XSSFCellStyle oddStyle = workbook.createCellStyle();
            oddStyle.setFillForegroundColor(new XSSFColor(new java.awt.Color(randInt(125, 255), randInt(125, 255), randInt(125, 255))));
            oddStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

//JDBC CONFIGURATIONS
            Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
            String dbURL = "jdbc:derby://localhost:1527/DATABASE_NAME;create=true;user=USER_ID;password=PASSWORD";

            Connection connection = DriverManager.getConnection(dbURL);
            Statement st = connection.createStatement();
            ResultSet resultSet = st.executeQuery("Select * from TABLE_NAME");
            ResultSetMetaData metaData = resultSet.getMetaData();
            int colCount = metaData.getColumnCount();

            SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");



            for (int curColIndx = 0; curColIndx < colCount; curColIndx++) {
                XSSFCell cell = rowHead.createCell((short) curColIndx);
                cell.setCellStyle(headStyle);
                cell.setCellValue(metaData.getColumnName(curColIndx + 1));
            }
            int index = 1;
            while (resultSet.next()) {
                XSSFRow row = sheet.createRow((short) index);

                for (int curColIndx = 0; curColIndx < colCount; curColIndx++) {
                    XSSFCell cell = row.createCell((short) curColIndx);
                    if (index % 2 == 1) {
                        cell.setCellStyle(oddStyle);
                    }
                     else {
                        cell.setCellStyle(evenStyle);
                    }
                    int type = metaData.getColumnType(curColIndx + 1);
                    if (type == Types.TIMESTAMP) {
                        cell.setCellValue(sdf.format(resultSet.getDate(curColIndx + 1)));
                    } else if (type == Types.VARCHAR || type == Types.CHAR) {
                        cell.setCellValue(resultSet.getString(curColIndx + 1));
                    } else {
                        cell.setCellValue(resultSet.getLong(curColIndx + 1));
                    }
                }

                index++;
            }
            baoStream = new ByteArrayOutputStream();
            try {
//This Writes 27,842 bytes xlsx file to disk for sample data.
                workbook.write(out);
//same workbook is written to ByteArrayOutputStream()
                workbook.write(baoStream);
//But, baoStream size is 49022bytes and After Encryption and Zipping It Creates File of Size 43,084 bytes.
                System.out.println("baoStream.size() :" + baoStream.size());
                try {
                    //byte[] bytesToWrite = getBytesFromFile();
                    byte[] bytesToWrite = baoStream.toByteArray();
                    InMemoryOutputStream inMemoryOutputStream = new InMemoryOutputStream();

                    zos = new ZipOutputStream(inMemoryOutputStream);

                    ZipParameters parameters = new ZipParameters();
                    parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
                    parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                    parameters.setFileNameInZip(xlsxFileName);
                    parameters.setSourceExternalStream(true);

                    zos.putNextEntry(null, parameters);
                    zos.write(bytesToWrite);
                    zos.closeEntry();
                    zos.finish();
                    zos.close();

                    // Write contents in our InMemoryOutputStream to a zip file to test if this worked
                    writeContentsToZipFile(inMemoryOutputStream);

                } catch (Exception e) {
                    e.printStackTrace();
                }

                out.close();
                resultSet.close();
                connection.close();
                System.out.println("Excel written successfully..");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            System.out.println("Exception is :" + e.toString());
        }
    }

    public ZipCreationInMemory() {
        //testZipCreationInMemory();
        createXlsxFile();
    }


package zipconversion;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Writes the content to memory.
 *
 */
public class InMemoryOutputStream extends OutputStream {

    // As we cannot know the size of the zip file that is being created,
    // we cannot maintain a byte array. We will copy all the bytes that
    // gets passed in the write() method to a List. Once all writing is done,
    // we can create a byte array from this List and this will be the content
    // of the zip file
    private List byteList;

    // flag to keep track if the outputstream is closed
    // no further write operations should be performed once this stream is closed
    private boolean closed;

    public InMemoryOutputStream() {
        byteList = new ArrayList();
        closed = false;
    }

    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("trying to write on a closed output stream");
        }

        byteList.add(Integer.toString(b));
    }

    public void write(byte[] b) throws IOException {
        if (b == null) {
            return;
        }
        write(b, 0, b.length);
    }

    public void write(byte[] b, int off, int len) throws IOException {
        if (closed) {
            throw new IOException("trying to write on a closed output stream");
        }

        if (b != null && len > 0) {
            for (int i = 0; i < len; i++) {
                byteList.add(Byte.toString(b[i]));
            }
        }
    }

    public byte[] getZipContent() {
        if (byteList.size() <= 0) {
            return null;
        }

        byte[] zipContent = new byte[byteList.size()+1];

        for (int i = 0; i < byteList.size(); i++) {
            zipContent[i] = Byte.parseByte((String) byteList.get(i));
        }
            return zipContent;
    }

    public void close() throws IOException {
        closed = true;
    }
}

1 个答案:

答案 0 :(得分:0)

方法writeContentsToZipFile(inMemoryOutputStream)中可能存在错误,但您没有发布它的源代码......

我认为class InMemoryOutputStream的实施不是必需的,它不起作用并导致更多问题。

  • 如果要将zip内容保存到文件,请将其替换为FileOutputStream
  • 如果要将zip内容保存在内存中,请将其替换为ByteArrayInputStream inMemoryOutputStream = new ByteArrayInputStream(bytesToWrite.length);

注意:zos.putNextEntry(null, parameters)的第一个参数为null。 它适用于parameters.setSourceExternalStream(true)。在此模式下,文件名和其他参数通过ZipParameters提供。

相关问题