I try to create a zip file and on-the-fly via NanoHTTPD
That is what I currently have:
#Override
public Response serve(IHTTPSession session) {
String uri = session.getUri();
if (uri.toString().equals("/test.zip")) {
try {
PipedOutputStream outPipe = new PipedOutputStream();
ZipEncryptOutputStream zeos = new ZipEncryptOutputStream(outPipe, "Foo");
ZipOutputStream zos = new ZipOutputStream(zeos);
File file = new File("Test.txt");
PipedInputStream inPipe = new PipedInputStream(outPipe, 2048);
ZipEntry ze = new ZipEntry("Test.txt");
zos.putNextEntry(ze);
FileInputStream fis = new FileInputStream(file);
IOUtils.copy(fis, zos);
fis.close();
zos.closeEntry();
zos.close();
return newChunkedResponse(Response.Status.OK, "application/zip", inPipe);
But when debugging - of course - takes some time, because everything is saved to the ZIP file first.
I guess I have to do the writing to zos somehow in a call back and after wards close the entry and stream? But how?
Is that an efficient way of doing it (I am aiming on Android) ? Creating temp files would be much easier - but it should work on low-end smartphones and also the initial wait of creating the zip file (around 40 MB) should be low when downloading.
Related
There are already many similar questions and tutorials available about this topic still I didn't found what I wanted to do.
I want to make an API, though which I can upload the zip file, that zip is containing xml files I am reading those files and sending the content as response.
The only problem here is currently I am storing the file inside of my project directory, but I don't want that I want to read the file directly without storing it in an directory.
So basically user will hit my API, upload the file and in response he will get the data present inside of files in that zip.
My Code:
#RequestMapping(value ="/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Object> uploadFile(#RequestParam("file")MultipartFile file) throws IOException {
System.out.println(file.getOriginalFilename());
File converFile = new File("src/main/"+file.getOriginalFilename());
converFile.createNewFile();
FileOutputStream fout = new FileOutputStream(converFile);
fout.write(file.getBytes());
//unzipping file and reading data;
String zipFileName = "src/main/"+file.getOriginalFilename();
List<String> str = new ArrayList<String>();
byte[] buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName));
ZipEntry zipEntry;
int read;
while ((zipEntry = zis.getNextEntry())!= null) {
while ((read = zis.read(buffer, 0, 1024)) >= 0) {
str.add(new String(buffer,0,read));
}
}
while (zipEntry != null){
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
System.out.println("Unzip complete");
System.out.println("--------------------------------");
System.out.println("List"+ str);
fout.close();
return new ResponseEntity<>(str, HttpStatus.OK);
}
This code is working fine uploading file saving it in project directory (src/main) and reading file data and giving the data as response.
How can I eliminate the saving part and do all these in code only.
You can use ByteArrayInputStream instead of FileInputStream, like this:
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(file.getBytes()));
I am trying to read extract a given file from zip file. Zip file contains directories & sub-directories as well. I tried Java7 nio file apis but since my zip has subdirectories as well, I need to provide complete path to extract the file, which is not suitable in my scenario. As I have to take filetobeextracted input from user. I have been trying below code for it but somehow read method of ZipInputStream not reading any contents to buffer. On debugging I found out that ZipEntry object value is null inside ZipInputStream due to its read method simply returns -1.But now I am stuck as I am not able to figure out how that value is being set for it.
try(OutputStream out=new FileOutputStream("filetoExtract");) {
zipFile = new ZipFile("zipFile");
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = e.nextElement();
if (!entry.isDirectory()) {
String entryName = entry.getName();
String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
System.out.println(i++ + "." + entryName);
if (searchFile.equalsIgnoreCase(fileName)) {
System.out.println("File Found");
BufferedInputStream bufferedInputStream = new BufferedInputStream(zipFile.getInputStream(entry));
ZipInputStream zin = new ZipInputStream(bufferedInputStream);
byte[] buffer = new byte[9000];
int len;
while ((len = zin.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.close();
break;
}
}
}
} catch (IOException ioe) {
System.out.println("Error opening zip file" + ioe);
}
Please advice what I am doing wrong here. Thanks
EDIT:
After debugging little more I found out that ZipFile class has inner class of similar name(ZipFileInputStream). So it was creating object of it rather than the outside ZipFileInputStream class. So I tried out below code and it worked out well. But I don't quite understand things here, what has happened. If someone could help me logic behind the scenes would be really great.
// BufferedInputStream bufferedInputStream = new
//BufferedInputStream(zipFile.getInputStream(entry));
//ZipInputStream zin = new ZipInputStream(bufferedInputStream);
InputStream zin= zipFile.getInputStream(entry);
The second line is unnecessary, as zipFile.getInputStream(entry) already returns an InputStream that represents the decompressed data. Therefore there's no need (or in fact it's wrong) to wrap that InputStream in yet another ZipInputStream:
BufferedInputStream bufferedInputStream = new BufferedInputStream(zipFile.getInputStream(entry));
ZipInputStream zin = new ZipInputStream(bufferedInputStream);
i am currently creating a zip file and filling it with various json files and images. All this should only run in memory and not on the hard disk. Therefore I have the following construct so far:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zip = null;
String FILE_NAME = "file.zip";
try {
zip = new ZipOutputStream(baos);
//now the critical part where the name of the file should be set
ZipEntry entry = new ZipEntry(FILE_NAME);
zip.putNextEntry(entry);
byte[] data = FILE_NAME.getBytes();
zip.write(data, 0, data.length);
zip.closeEntry();
//end of critical part and filling the rest of the zip
//...
//
}finally{
IOUtils.closeQuietly(zip);
byte[] byteFile = baos.toByteArray();
IOUtils.closeQuietly(baos);}
The problem is that the zip-file is called file.zip, but also contains a file.zip itself.
How can I name my Zip file from the ZipOutputStream without packing into this one file with the same name? Unfortunately I only found this solution here.
public byte[] zipBytesFile(List<byte[]> files) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
int i = 0;
for (byte[] file : files) {
ZipEntry entry = new ZipEntry(++i + ".pdf");
entry.setSize(file.length);
zos.putNextEntry(entry);
zos.write(file);
}
zos.closeEntry();
zos.close();
return baos.toByteArray();
}
I have a question regarding dynamically creating and streaming ZIP files. I have multiple large files stored on remote HTTP servers (for example Amazon S3).
Now I want the user to download let's say 100 files as one ZIP file.
I could download all 100 files, zip them and stream them to the user, but that would be wasting lots of resources. So my approach is download the first file, stream it to the user, download the next file, stream it to the user and so on.
This is the test code:
public class TestController extends Controller {
public Result test() throws Exception {
InputStream is = getDynamicStreamSomewhere();
response().setContentType("application/zip");
response().setHeader("Content-Disposition", "attachment;filename=test.zip");
return ok(is);
}
private InputStream getDynamicStreamSomewhere() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
String url1 = "http://www.example.com/largefile1.bin";
String url2 = "http://www.example.com/largefile2.bin";
ZipEntry entry1 = new ZipEntry("file1.bin");
zos.putNextEntry(entry1);
URL website = new URL(url2);
InputStream in = website.openStream();
IOUtils.copy(in, zos);
in.close();
zos.closeEntry();
ZipEntry entr2 = new ZipEntry("file2.bin");
zos.putNextEntry(entr2);
URL websitea = new URL(url1);
InputStream ina = websitea.openStream();
IOUtils.copy(ina, zos);
ina.close();
zos.closeEntry();
return new ByteArrayInputStream(baos.toByteArray());
}
}
But as far as I debugged it, that does not really stream file by file but download everything and then stream it to the user.
What I am missing is something like flushing the output buffer to the user after every file (or maybe after each 4KB block).
I know how to do it with Java servlets, but not with Play Framework. Any help is appreciated!
Thank you!
I made an upload file servlet, summed up like this:
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
InputStream stream = item.openStream()
File file = new File(path +"/"+ item.getFieldName));
FileOutputStream fout= new FileOutputStream (file);
BufferedOutputStream bout= new BufferedOutputStream (fout);
BufferedInputStream bin= new BufferedInputStream(stream);
byte buf[] = new byte[2048];
while ((bin.read(buf)) != -1){
bout.write(buf);
}
bout.close();
bin.close();
}
I used streams so that the file isn't loaded in memory.
The files are being uploaded smoothly, but I cannot open the resulted file (error differs depending on file type). Also the size of the resulted file is larger then the one of the original.
I tried different types of stream readers and writers but couldn't get any closer, and I couldn't find a similar problem.
I ruled out encoding as I am receiving and writing bytes, so encoding doesn't matter, right?
What could be the problem?
You're writing all the content of buf array. This could be the problem for last read.
Change the while loop like this:
int n;
while ((n = bin.read(buf)) != -1)
{
bout.write(buf, 0, n);
}