Unable to open S3 zip file downloaded using spring-boot - java

My AWS S3 contains some files and I want to download those files through my application as a zip file. I'm able to download the zip file successfully but while the file I'm getting an error Unexpected end of archive and also the CSV file size is 0 inside the zip.
I did dig a lot but not able to understand the exact solutions.
Here's the code:
String zipFileName = "MyZipFile.zip";
String fileName = "test.csv";
filePath = new String(Base64.getDecoder().decode(filePath));
System.out.println("file:" + filePath);
// get file from S3
S3Object s3Obj = awsClient.downloadFile(filePath);
byte[] s3Bytes = s3Obj.getObjectContent().readAllBytes();
// create zip
ByteArrayOutputStream byteArrOutputStream = new ByteArrayOutputStream(s3Bytes.length);
ZipOutputStream zipOutStream = new ZipOutputStream(byteArrOutputStream);
ZipEntry zip = new ZipEntry(fileName);
zipOutStream.putNextEntry(zip);
zipOutStream.write(s3Bytes, 0, s3Bytes.length);
byte[] streamBytes = byteArrOutputStream.toByteArray();
// close streams
zipOutStream.closeEntry();
zipOutStream.close();
closeQuietly(byteArrOutputStream);
// prepare download
System.out.println("streamBytes:" + streamBytes + " len:" + streamBytes.length);
System.out.println("s3Bytes:" + s3Bytes + " len:" + s3Bytes.length);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(streamBytes.length);
headers.setContentDispositionFormData("attachment", zipFileName);

I think you should close your zip output stream to have everything written to the underlying byte array stream before you extract the byte array... Ie reorder the lines to:
// close streams
zipOutStream.closeEntry();
zipOutStream.close();
byte[] streamBytes = byteArrOutputStream.toByteArray();
closeQuietly(byteArrOutputStream);

Related

Transferring files from AWS lambda tmp folder to sftp server

I have created a AWS lambda function that takes some files from an S3 bucket, zips them and transfers the zipped file to a sftp server. When I look in the server, I see that the tmp folder has been carries over with the files and a tmp folder gets created inside the zip file. When I open the zip file, there is a tmp folder and inside that folder are the files that I had zipped. I have scoured the internet and AWS trying to figure out how to change the directory in AWS Lambda when I am retrieving the files to be zipped, but have not had any luck. I don't want to have a tmp folder in my zip file. When I unzip the zip file, I just want to see the files that I had selected to be zipped without any folders. Does anyone know how to do this? I am programming in Java.
My code is below.
private DownloadFile(){
File localFile = new File(fileName);
//pull data and audit files from s3 bucket
s3Client.getObject(new GetObjectRequest("pie-dd-demo/daniel20", fileName), localFile);
zipOS = new ZipOutputStream(fos);
//send files to be zipped
writeToZipFile(fileName, zipOS);
}
public static void writeToZipFile(String path, ZipOutputStream zipStream)
throws FileNotFoundException, IOException {
File aFile = new File(path);
FileInputStream fis = new FileInputStream(aFile);
ZipEntry zipEntry = new ZipEntry(path);
try {
zipStream.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipStream.write(bytes, 0, length);
System.out.println(path + "write to zipfile complete");
}
} catch (FileNotFoundException exception) {
// Output expected FileNotFoundExceptions.
} catch (Exception exception) {
// Output unexpected Exceptions.
}
zipStream.closeEntry();
fis.close();
}
I think the problem is that you are creating a zip entry using new ZipEntry(path) and that means that the resulting zip file will contain the full path as the name of the zip entry.
You can retrieve the actual filename from a full path/file in Java as follows:
File f = new File("/tmp/folder/cat.png");
String fname = f.getName();
You can then use fname to create the zip entry by calling new ZipEntry(fname).

how to flush two files from HTTPServeletResponse simultaneously

I am in a situation where on calling an API i want to download a excel file along with a zip file.
I have cracked the code for downloading them separately, but when put together only one file gets downloaded and the other one just doesnt gets downloaded.
I guss the problem is I cannot use response.getOutPutStream().flush() or response.flushBuffer() simultaneously.
String absolutePath = context.getRealPath("resources/ZipFolders");
String inputFile = Paths.get(absolutePath + "/Attachments.zip").toAbsolutePath().toString();
File finalFile = new File(inputFile);
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(finalFile));
String absolutePath2 = context.getRealPath("resources/Spreadsheets");
String inputFile2 = Paths.get(absolutePath2 + "/Validation_Spreadsheet.xlsx").toAbsolutePath().toString();
File file = new File(inputFile2);
byte[] bytes = IOUtils.toByteArray(new FileInputStream(file));
ZipEntry zipEntry = new ZipEntry("Validation_Spreadsheet.xlsx");
zipOut.putNextEntry(zipEntry);
zipOut.write(bytes);
zipOut.closeEntry();
zipOut.close();
response.setContentType("application/zip");
response.setHeader("Content-disposition", "attachment;filename=attachment_trial.zip");
response.getOutputStream().write(IOUtils.toByteArray(new FileInputStream(finalFile)));
System.err.println("above flush>>>>>>>>>>>>>>");
response.getOutputStream().flush();
responsetrial.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
responsetrial.setHeader("Content-disposition", "attachment; filename=TransactionErrors.xlsx");
responsetrial.getOutputStream().write(IOUtils.toByteArray(new FileInputStream(file)));
System.err.println("above flush2>>>>>>>>>>>>>>");
responsetrial.getOutputStream().flush();
It's not possible to download 2 files over a single HTTP request.
You will need to make 2 separately requests for this task.
If you need to download many files in a single "HTML button", you need to write some javascript logic two make this.

Create zip file to local machine

I have a below code in which my zip file is getting created on the server machine, i want the zip file to be created in the local machine, below is my code, please check the below code and let me know if anybody has a solution for it .
<%!
public static void addToZipFile(String fileName, ZipOutputStream zos) throws FileNotFoundException, IOException {
System.out.println("Writing '" + fileName + "' to zip file");
File file = new File(fileName);
FileInputStream fis = new FileInputStream(file);
ZipEntry zipEntry = new ZipEntry(file.getName());
zos.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zos.write(bytes, 0, length);
}
zos.closeEntry();
fis.close();
}
%>
<%
String imgID = request.getParameter("iID").toString();
String epsFile = request.getParameter("epsNm").toString();
String ZipFile = imgID + ".zip";
//FileOutputStream fos = new FileOutputStream("d:/" + ZipFile);
FileOutputStream fos = new FileOutputStream(ZipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
File temp = new File(imgID);
String absolutePath = temp.getAbsolutePath();
System.out.println("filepath" + absolutePath);
String relativeWebPath = "CoverCapPDF/"+ imgID;
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
System.out.println("absoluteDiskPath" + absoluteDiskPath);
String relativeWebPathEPS = "eps/"+ epsFile;
String absoluteDiskPathEPS = getServletContext().getRealPath(relativeWebPathEPS);
System.out.println("absoluteDiskPath" + absoluteDiskPathEPS);
String file1Name = absoluteDiskPath;
String file2Name = absoluteDiskPathEPS;
String file3Name = "file2.txt";
addToZipFile(file1Name, zos);
addToZipFile(file2Name, zos);
zos.close();
fos.close();
%>
please help me :)
I am assuming you are dealing with a web application which uses JSP (since the above syntax suggests the same). The answer then is you cannot.
What you can do is
Create the file at the server and ask the client to download refer here
Create an applet and the applet can have the zip code (though not recommended for security reasons)
First of all, you should not use a JSP for this, but a servlet. JSPs are view components, whose role is to generate HTML markup using the JSP EL, the JSTL and other custom tags, but no scriptlet.
Second: you're writing to a FileOutputStream. that obviously writes your zip entries to a file. You want to write your zip entries to the HTTP response. You should thus use the response output stream to write your zip entries.
To tell the browser that you're sending what should be saved as a zip file, use
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
(this should be called before sending anything to the response output stream)

android : Zip Folder is invalid

i have a created 3 xml files and compressed into a zip folder . The folder is send from server. When i download the zip folder through browser, its working properly and can extract the files. But when i download it from android application and store in SD card, it is corrupted. I pulled the file from SD card to computer and tried to extract the folder, it shows Zip Folder is invalid . My code is given below :
DefaultHttpClient httpclient1 = new DefaultHttpClient();
HttpPost httpPostRequest = new HttpPost(
Configuration.URL_FEED_UPDATE);
byte[] responseByte = httpclient1.execute(httpPostRequest,
new BasicResponseHandler()).getBytes();
InputStream is = new ByteArrayInputStream(responseByte);
// ---------------------------------------------------
File file1 = new File(Environment
.getExternalStorageDirectory() + "/ast");
file1.mkdirs();
//
File outputFile = new File(file1, "ast.zip");
FileOutputStream fos = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
When I used
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(is));
The ZipInputStream can't store values from stream.
I'd guess that your main mistake is where you get the input stream. What you are actually doing is to get the server response as String (BasicResponseHandler) and then converting that to bytes again. Since Java is all UTF-8 this most likely does not work.
Better try something like
HttpResponse response = httpclient1.execute(httpPostRequest);
InputStream is = response.getEntity().getContent()
(And do better null pointer checking, read the content in a try-catch block and make sure you close all resources in a finally block.)

FTP zip file extract Error

I am trying to extract zip files from the server(A zip file is in the server.so I am trying to extract that through the FTP) and I am using this code,
byte[] buf = new byte[1024];
ZipInputStream zinstream = new ZipInputStream(Home.ftpClient.retrieveFileStream("HO2BR.br.3162675983055490721.zync"));
ZipEntry zentry = zinstream.getNextEntry();
System.out.println("Name of current Zip Entry : " + zentry + "\n");
while (zentry != null) {
String entryName = zentry.getName();
System.out.println("Name of Zip Entry : " + entryName);
FileOutputStream outstream = new FileOutputStream(entryName);
int n;
while ((n = zinstream.read(buf, 0, 1024)) > -1) {
outstream.write(buf, 0, n);
}
System.out.println("Successfully Extracted File Name : " + entryName);
outstream.close();
zinstream.closeEntry();
zentry = zinstream.getNextEntry();
}
zinstream.close();
}
ZipInputStream(Home.ftpClient.retrieveFileStream("HO2BR.br.3162675983055490721.zync"));
to Input stream assign the FTPClient 's retrieveFileStream
while executing the program this error is occurred
java.util.zip.ZipException: invalid distance too far back
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:164)
How can I solve this exception?
Most likely the ftpClient.retrieveFileStream does not support seeking. The Zip "table of contents" entries occur at the very end of the file. So, "opening" the first item requires the ability to back up to the start of the file to read that item.
You'll need to download the zip file to a local file, then extract the contents from there.
The solution is to change the transfer mode from ASCII to BINARY

Categories