Create ZIP file at run time in GAE Java application

On GAE, we can not use FileOutputStream to write content into a file, you can get the reason from this Q&A. But, if we need to create zip file, how could we do? We can use ByteArrayOutputStream, ByteArrayInputStream and Blob to accomplish this job. But we needed to define some beans, it included at least blob and file name variables. Before we ready to return zip file. All data must be handled by these beans.

Java file upload example can refer to this article. Why we need to define bean object to handle data? Why we do not use FileItemStream directly? It look like an unnecessary move. If we do not only to retrieve information from an upload file, but also to generate new files. Define bean object can give us a consistent approach to deal with data like File object.

Here, I will demo a simple case. There is a text file that has multiline content. The program will separate it into one line per file. Finally, compress these new text files and return to download.

This case has three steps.
  1. There is a servlet to receive uploaded file.
  2. Separate text file into one line per file.
  3. Compress these file into one zip file and return to download.
Demo & Download

Servlet:
// Receive uploaded file
ServletFileUpload fileUpload = new ServletFileUpload();
FileItemIterator itemIterator = fileUpload.getItemIterator(req);
FileItemStream itemStream = itemIterator.next();
InputStream stream = itemStream.openStream();

byte[] bs = new byte[8192];
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();

int len;
while ((len = stream.read(bs, 0, bs.length)) != -1) {
      arrayOutputStream.write(bs, 0, len);
}
           
// Save file as byte array into blob object
Blob blob = new Blob(arrayOutputStream.toByteArray());
stream.close();
arrayOutputStream.close();
           
// UploadedFile bean object
UploadedFile uploadedFile = new UploadedFile();
uploadedFile.setName(itemStream.getName());
uploadedFile.setBlob(blob);

CommonUtil util = new CommonUtil();
           
// Separate text file into one line per file.
List generatedFiles = util.separateFile(uploadedFile);
// Compress into zip file.
Blob zipFile = util.toZip(generatedFiles);
           
// Set response content type
resp.setContentType("application/octet-stream");
// Set response header
resp.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
           
// return to download
resp.getOutputStream().write(zipFile.getBytes());


Separate text file into one line per file:
// New file list
List generatedFiles = new ArrayList();

// Read uploaded file
Scanner scanner = new Scanner(new ByteArrayInputStream(uploadedFile
       .getBlob().getBytes()));
       
int i = 0;
while(scanner.hasNextLine()) {
           
     i++;
           
     String str = scanner.nextLine();
           
     // Use GeneratedFile bean to handle new file
     GeneratedFile file = new GeneratedFile();
     file.setBlob(new Blob(str.getBytes()));
     file.setName("Line" + Integer.toString(i) + ".txt");
           
     generatedFiles.add(file);
}
       
scanner.close();


Compress:
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(arrayOutputStream);

for (int i = 0, max = files.size(); i < max; i++) {

       GeneratedFile file = files.get(i);
       zos.putNextEntry(new ZipEntry(file.getName()));
       zos.write(file.getBlob().getBytes());

       zos.closeEntry();
}

arrayOutputStream.flush();
zos.flush();
arrayOutputStream.close();
zos.close();

Blob blob = new Blob(arrayOutputStream.toByteArray());

return blob;

留言

熱門文章