Skip to content
Advertisement

Serving a zip file generated in server and stored in memory

I need to generate a bunch of xml files with data from my java based web system, that represent a whole export of another system based in XML. Such system will accept this import later.

My approach is to create all files in memory, then save each one as entries it to a zip also in memory, which later is served to the client.

The data flow is working perfectly, but somehow the output is a blank file. I think I got wrong the outputstream structure

This is the part that I might be getting wrong: …

 //ZIP creation in server memory
                ByteArrayOutputStream datosEnMemoria = new ByteArrayOutputStream();
                ZipOutputStream zipped_out = new ZipOutputStream(datosEnMemoria)

                    //close and zip entry
                    xmlData.append(Tangonet.terminarCargaRegistros());
                    byte[] xmlBinData = xmlData.toString().getBytes();
                    zipped_out.write(xmlBinData, 0, xmlBinData.length);
                    zipped_out.closeEntry();
                }
                byte[] zipped_out_size = zipped_out.toString().getBytes();

                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");
                response.setHeader("Content-length", "" + zipped_out_size.length);
                response.setHeader("Content-Type", "application/zip");
                response.setHeader("Content-Type", "application/octet-stream");
                response.setHeader("Content-Transfer-Encoding", " binary");
                //closing zip and send it to client
                zipped_out.flush();
                zipped_out.close();
//                out.flush();
//                out.close();

This is the full code:

@RequestMapping(value = "/cierreZ/exportar", method = RequestMethod.GET)
    public void cierreZExportar(@ModelAttribute InformesFinancierosForm informesFinancierosForm, HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession(true);
        String fechaInicio = null;
        String fechaFin = null;

        if (session.getAttribute("mesActual") != null) {
            informesFinancierosForm.setFechaInicio("01-" + informesFinancierosForm.getMes());
            informesFinancierosForm.setFechaFin(new SimpleDateFormat("dd-MM-yyyy").format(DateUtil.getUltimoDiaDelMes(DateUtil.traduceDateDate((String) session.getAttribute("fechaIni")))));
            fechaInicio = informesFinancierosForm.getFechaInicio();
            fechaFin = informesFinancierosForm.getFechaFin();
        } else {
            fechaInicio = (String) session.getAttribute("fechaIni");
            fechaFin = (String) session.getAttribute("fechaFin");
        }

        if (informeService.isRangoFechaValido(informesFinancierosForm.getSalasSeleccionadas(), fechaInicio)) {
            if (!(fechaInicio.compareTo("") == 0) || (fechaFin.compareTo("") == 0)
                    || informesFinancierosForm.getSalasSeleccionadas().length == 0) {

//                ServletOutputStream out = response.getOutputStream();
                List<InformeCierreZItemForm> listadoInfCierreZ = cierreZService.getCierres(informesFinancierosForm.getSalasSeleccionadas(), fechaInicio, fechaFin);

                //ZIP creation in server memory
                ByteArrayOutputStream datosEnMemoria = new ByteArrayOutputStream();
                ZipOutputStream zipped_out = new ZipOutputStream(datosEnMemoria);

                //filling zip with static xml files
                for (int i = 0; i < Tangonet.documentos_estaticos_tangonet.length; i++) {
                    ZipEntry xmlFile = new ZipEntry(Tangonet.documentos_estaticos_tangonet[i][0] + ".xml");
                    zipped_out.putNextEntry(xmlFile);

                    StringBuilder xmlData = new StringBuilder();
                    xmlData.append(Tangonet.documentos_estaticos_tangonet[i][1]);

                    byte[] xmlBinData = xmlData.toString().getBytes();
                    zipped_out.write(xmlBinData, 0, xmlBinData.length);
                    zipped_out.closeEntry();
                }

                //filling zip with dynamic xml files
                for (int i = 0; i < Tangonet.documentos_dinamicos_tangonet.length; i++) {

                    //dynamic xml creation
                    ZipEntry xmlFile = new ZipEntry(Tangonet.documentos_dinamicos_tangonet[i][0] + ".xml");
                    zipped_out.putNextEntry(xmlFile);

                    //xml schema
                    StringBuilder xmlData = new StringBuilder();
                    xmlData.append(Tangonet.documentos_dinamicos_tangonet[i][1]);

                    //xml data rows
                    for (InformeCierreZItemForm informeCierreZActual : listadoInfCierreZ) {
                        Sala salaActual = informeCierreZActual.getSala();
                        CierrezList CierresZ = cierreZService.getCierresZ(salaActual, fechaInicio, fechaFin);

                        //fiscal data in rows
                        Tangonet datosFiscalesCierrezActual = tangonetDatos.getDatosFiscales(salaActual);

                        for (Cierrez cierreActual : CierresZ) {
                            if (Tangonet.documentos_dinamicos_tangonet[i][0].equals("Comp_de_FacturaciĆ³n_para_Cobranza_Centralizada___GVA12")) {
                                xmlData.append(datosFiscalesCierrezActual.crearRegistroGVA12(cierreActual));
                            } else {
                                xmlData.append(datosFiscalesCierrezActual.crearRegistroGVA42(cierreActual));
                            }
                        }
                    }
                    //close and zip entry
                    xmlData.append(Tangonet.terminarCargaRegistros());
                    byte[] xmlBinData = xmlData.toString().getBytes();
                    zipped_out.write(xmlBinData, 0, xmlBinData.length);
                    zipped_out.closeEntry();
                }
                byte[] zipped_out_size = zipped_out.toString().getBytes();

                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");
                response.setHeader("Content-length", "" + zipped_out_size.length);
                response.setHeader("Content-Type", "application/zip");
                response.setHeader("Content-Type", "application/octet-stream");
                response.setHeader("Content-Transfer-Encoding", " binary");
                //closing zip and send it to client
                zipped_out.flush();
                zipped_out.close();
//                out.flush();
//                out.close();
            }
        }
    }

Advertisement

Answer

Zip file can be big, so don’t generate it in memory. Write it straight to client.

Also:

  • Don’t set Content-Type three times. It can only have one value.

  • Don’t specify Content-Transfer-Encoding. It’s an email header, not an HTTP header.

  • Since you’ll be streaming, don’t specify Content-length.

// headers must be set before streaming
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=cierresZ_a_tangonet" + java.time.LocalDate.now() + ".zip");

// stream straight to client
ZipOutputStream zipped_out = new ZipOutputStream(response.getOutputStream());

// Add zip entries and data here:
// Loop:
//    zipped_out.putNextEntry(...)
//    Generate XML, writing it straight to zipped_out
//      Remember to flush any streams/writers wrapped around zipped_out
//      Do not close zipped_out or wrappers of it
//        If that cannot be prevented, use a CloseShieldOutputStream (from Commons IO)
//    No need to call zipped_out.closeEntry()

// make sure to finish the zip stream
zipped_out.finish();
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement