I'd like to download multiple files from some external source like S3, create a single zip
file containing all those files and present the user a link to download that zip
file.
Obviously I can process the files sequentially, reading the input stream of each one and writing it to ZipOutputStream
.
How can I read all the input file streams in parallel and write to a single output stream so that I can present a download link to the user without making them wait until zip
file is fully written?
My current code:
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);
}
}
If you have Visual Studio with the AWS Explorer extension installed, you can also browse to Amazon S3 (step 1), select your bucket (step 2), select al the files you want to download (step 3) and right click to download them all (step 4).
You can copy an object from one bucket to another by using the AmazonS3 client's copyObject method. It takes the name of the bucket to copy from, the object to copy, and the destination bucket name. s3. copyObject(from_bucket, object_key, to_bucket, object_key); } catch (AmazonServiceException e) { System.
While downloading multiple files, we can create a zip file in spring boot and download that zip file alone rather then downloading multiple files individually. For this purpose, we first need to create a zip file in spring boot and then set the content type as application/zip to download the zip file.
Read stream for very first file & start writing it to outputstream
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletOutputStream sos = response.getOutputStream();
ZipOutputStream zos = new ZipOutputStream(sos);
try {
S3ServiceWrapper s3Service = new S3ServiceWrapper();
ZipEntry zipentry = null;
byte bytes[] = new byte[4096];
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=java-s3-download.ZIP");
for (String objectKey : objectKeys) {
String name = objectKey.substring(objectKey.lastIndexOf("/"), objectKey.length());
log.info("Start Writing File::" + name);
zipentry = new ZipEntry(name);
zos.putNextEntry(zipentry);
InputStream in = s3Service.downloadFileAsStream(bucketName, objectKey);
int bytesRead = -1;
while ((bytesRead = in.read(bytes)) != -1) {
zos.write(bytes, 0, bytesRead);
}
log.info("Finsih Writing File::" + name);
in.close();
}
} catch (Exception e)
{
e.printStackTrace();
} finally {
zos.flush();
zos.closeEntry();
zos.close();
sos.close();
}
}
public InputStream downloadFileAsStream(String bucketName, String objectKey) {
if (s3Service == null) {
return null;
}
try {
GetObjectRequest s3ObjectReq = new GetObjectRequest(bucketName, objectKey);
log.info("Downloading file having key = " + objectKey);
long startTime=System.currentTimeMillis();
S3Object downlodedObjectMD = s3Service.getObject(s3ObjectReq);
log.info("Time to load Stream is "+(System.currentTimeMillis()-startTime)+" ms");
return downlodedObjectMD.getObjectContent();
} catch (Exception e) {
log.error("EXCEPTION = " + e.getMessage(), e);
}
return null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With