mabg
mabg

Reputation:

ZIP on the fly immediatelly

I need to generate a ZIP file with data on the fly from a servlet. I pass the ServletOutputSream to the ZipOutputStream constructor, and it does and send the ZIP to the client correctly. When the ZIP result is large, the servlet takes to answer a lot. I suppose that first creates the ZIP and after send it.

I make a helper class that wraps ZipOutputStream.

I need that when the flush method is called, the ZIP piece that is already generated, will be sent immediatelly. How can I do this?

public class ZIPResponse {

    private ZipOutputStream out;
    private HttpServletResponse response;
    private boolean isFirstEntry;
    private ConnectionManager con;

    public ZIPResponse(ConnectionManager con, OutputStream out) throws IOException {
        this.out = new ZipOutputStream(out);
        isFirstEntry = true;
        this.con = con;
    }

    public ZIPResponse(ConnectionManager con, HttpServletResponse response) throws IOException {
        this(con, response.getOutputStream());
        this.response = response;
        response.setCharacterEncoding("ISO-8859-1");
        sendNewEntry("con");
        flush();
    }

    public void sendNewEntry(String dataName) throws IOException {
        if (isFirstEntry) {
            isFirstEntry = false;
        } else {
            out.closeEntry();
        }
        out.putNextEntry(new ZipEntry(dataName));
    }

    public void sendData(String dataName, String data) throws IOException {
        sendNewEntry(dataName);
        sendData(data);
    }

    public void sendData(byte[] bytes) throws IOException {
        out.write(bytes);
        flush();
    }

    public void sendData(String data) throws IOException {
        sendData(data.getBytes());
    }

    public void sendAndCloseData(String dataName, String data) throws IOException {
        sendNewEntry(dataName);
        sendData(data);
        close();
    }

    private void sendDataFile(String dataName, DataTransformer dt)
            throws IOException, SQLException {
        sendNewEntry(dataName);
        dt.sendResultSet(this);
    }

    public void sendDataFile(String dataName, ResultSet data, String[] columnsRestriction) throws IOException,
            SQLException {
        RestrictedDataTransformer dt = new RestrictedDataTransformer(data, columnsRestriction);
        sendDataFile(dataName, dt);
    }

    public void sendDataFile(String dataName, ResultSet data) throws IOException,
            SQLException {
        DataTransformer dt = new DataTransformer(data);
        sendDataFile(dataName, dt);
    }

    public void sendDataFile(String dataName, PreparedStatement p) throws
            SQLException, IOException {
        ResultSet data = p.executeQuery();
        sendDataFile(dataName, data);
    }


    public void sendDataFile(String dataName, String SQL, String[] columnsRestricted)
            throws DBException, SQLException, IOException {
        ResultSetStatement st = new ResultSetStatement(con, SQL);
        ResultSet valores = st.executeQuery();
        try {
            sendDataFile(dataName, valores, columnsRestricted);
        } finally {
            valores.close();
        }
    }

    public void sendDataFile(String dataName, String SQL) throws DBException, SQLException, IOException {
        ResultSetStatement st = new ResultSetStatement(con, SQL);
        ResultSet valores = st.executeQuery();
        try {
            sendDataFile(dataName, valores);
        } finally {
            valores.close();
        }
    }

    public void sendAndCloseDataFile(String dataName, ResultSet data) throws
            SQLException, IOException {
        sendDataFile(dataName, data);
        close();
    }

    public void sendAndCloseDataFile(String dataName, String SQL) throws DBException, SQLException, IOException {
        sendDataFile(dataName, SQL);
        close();
    }

    public void close() throws IOException {
        sendNewEntry("OK");
        out.closeEntry();
        out.close();
        flush();
    }

    public void flush() throws IOException {       
      out.flush();
      response.flushBuffer();
    }
}

Upvotes: 1

Views: 6491

Answers (3)

ics_mauricio
ics_mauricio

Reputation: 369

Here is my implementation:

String realpath = getServletContext().getRealPath("/");
    response.setContentType("application/zip");
    response.setHeader("Content-Disposition","attachment; filename="+fi.replace('/', '-')+"_"+ff.replace('/', '-')+".zip");
ServletOutputStream out = null;
ZipOutputStream zipfile = null;
try{
                List<Object[]> cfdis = /*my hibernate criteria source, your Database?*/

        out = response.getOutputStream();

        zipfile = new ZipOutputStream(out);
        ZipEntry zipentry = null;

        for(Object[] cfdi:cfdis){

            zipentry = new ZipEntry(cfdi[1].toString()+".xml");
            zipfile.putNextEntry(zipentry);

            InputStream in = new FileInputStream(new File(realpath+cfdi[0].toString()));


            byte[] bytes = new byte[FILEBUFFERSIZE];
            int bytesRead;
            while ((bytesRead = in.read(bytes)) != -1) {
                zipfile.write(bytes, 0, bytesRead);
            }
        }
}catch(...){}
finally{
   zipfile.close();
   out.close();
}

I hope you find this useful.

Upvotes: 1

Madhu
Madhu

Reputation: 5766

I guess your question is to send the zip content to response before you complete the zip creation. Yes, you can do this thru buffering.

For buffering follow Streaming large files in a java servlet

Upvotes: 0

CarlG
CarlG

Reputation: 1666

In case your client is flexible with what it receives, GZIP will work better for streaming compression.

Upvotes: 4

Related Questions