tags:

views:

286

answers:

3

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();
    }
}
+2  A: 

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

CarlG
A: 

I don't know about your ZipOutputStream, but if you would go with a commercial product like Xceed Real-Time Zip for .NET, you would get exactly what you need.

Martin Plante
A: 

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 http://stackoverflow.com/questions/55709/streaming-large-files-in-a-java-servlet

Madhu