I uploaded my zip archive to the server and want to open .txt and .jpg files in it. I successfully get my archive in my Controller and get the name of each file via ZipEntry. Now I want to open it but for this I should get a full path to my file.
I haven't found how I can do that. Could you suggest some approach how to do that ?
Update
I try to use example have been suggested below but I am not be able open the file
ZipFile zFile = new ZipFile("trainingDefaultApp.zip");
I have got the FileNotFoundException
So I return to my start point. I have upload form in Java Spring application. In controller I had got a zip archive as byte[]
#RequestMapping(method = RequestMethod.POST)
public String create(UploadItem uploadItem, BindingResult bindingResult){
try {
byte[] zip = uploadItem.getFileData().getBytes();
saveFile(zip);
Then I had got each ZipEntry
InputStream is = new ByteArrayInputStream(zip);
ZipInputStream zis = new ZipInputStream(is);
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
if (entryName.equals("readme.txt")) {
ZipFile zip = new ZipFile(entry.getName()); // here I had got an exception
According to docs I did all right but as for me it is strange to pass the file name only and suspect that you successfully will open the file
I resolve my uissue. The solution is work directly with ZipInputStream. Here the code:
private void saveFile(byte[] zip, String name, String description) throws IOException {
InputStream is = new ByteArrayInputStream(zip);
ZipInputStream zis = new ZipInputStream(is);
Application app = new Application();
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
if (entryName.equals("readme.txt")) {
new Scanner(zis); //!!!
//...
zis.closeEntry();
zipFile.getInputStream(ZipEntry entry) will return you the inputstream for the specific entry.
Check out the javadocs for ZipFile.getInputStream() - http://docs.oracle.com/javase/6/docs/api/java/util/zip/ZipFile.html#getInputStream(java.util.zip.ZipEntry).
Update:
I misread your question. For using the ZipInputStream, there is sample code on Oracle's website (http://java.sun.com/developer/technicalArticles/Programming/compression/) that shows you how to read from the stream. See the first code sample: Code
Sample 1: UnZip.java.
Copying here, it is reading from the entry and writing it directly to a file, but you could replace that with whatever logic you need:
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
System.out.println("Extracting: " +entry);
int count;
byte data[] = new byte[BUFFER];
// write the files to the disk
FileOutputStream fos = new FileOutputStream(entry.getName());
dest = new
BufferedOutputStream(fos, BUFFER);
while ((count = zis.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
}
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 have a requirement to split a 100mb zip file(which will be having sub folders and images) into 10 zip files(each of 10mb).Then I need to send each sliced zip files to an API (as multipart reauest), in receiver API i need to combine each of the above 10 zip files back to origin 100mb zip file.
Below is the code for slicing
public static void splitZip(String zipName, String location, String NewZip) throws IOException{
FileInputStream fis = new FileInputStream(location);
ZipInputStream zipInputStream = new ZipInputStream(fis);
ZipEntry entry = null;
int currentChunkIndex = 0;
long entrySize = 0;
ZipFile zipFile = new ZipFile(location);
Enumeration enumeration = zipFile.entries();
String copDest = zipCopyDest + "\\" + NewZip + "_" + currentChunkIndex +".zip";
FileOutputStream fos = new FileOutputStream(new File(copDest));
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);
long currentSize = 0;
try {
while ((entry = zipInputStream.getNextEntry()) != null && enumeration.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) enumeration.nextElement();
System.out.println(zipEntry.getName());
System.out.println(zipEntry.getSize());
entrySize = zipEntry.getSize();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
if((currentSize + entrySize) > MAX_FILE_SIZE) {
zos.close();
currentChunkIndex++;
zos = getOutputStream(currentChunkIndex, NewZip);
currentSize = 0;
}else{
currentSize += entrySize;
zos.putNextEntry(new ZipEntry(entry.getName()));
byte[] buffer = new byte[8192];
int length = 0;
while ((length = zipInputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
byte[] unzippedFile = outputStream.toByteArray();
zos.write(unzippedFile);
unzippedFile = null;
outputStream.close();
zos.closeEntry();
}
}
} finally {
zos.close();
}
}
When i extract slices zips manually i found some images are corrupted am not able to open it. Also am not getting a proper solution for combining the zip files. Thanks in advance.
Zip specification has a feature to split zip files to any desired length (minimum split length should be 64kb). Zip4j, supports this feature to create split zip files (documentation). You can then pass each split file to the api. The api can then use the merge functionality in zip4j to merge those split files into a single zip file. On a side note: even without merging, it is a perfectly valid zip file. as long as all the split zip files are in the same directory.
The approach will not work if you have any file in the zip greater than 10 mb and also the else condition should be executed in both the cases and in this approach you have to depend on the size of file in zip may be better you go with approach of not creating smaller zips
I need the InputStream for each entry of my zip (contains various files and folders) passed as a byte array.
This is what I have so far:
private void accessEachFileInZip (byte[] zipAsByteArray) throws IOException{
ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(zipAsByteArray));
ZipEntry entry = null;
while ((entry = zipStream.getNextEntry()) != null) {
ZipEntry currentEntry = entry;
InputStream inputStreamOfCurrentEntry = ???
zipStream.closeEntry();
}
zipStream.close();
}
There is a simple way doing this with a ZipFile instance by just calling getInputStream("EnrtryImLookingFor") like in this example:
ZipFile zipFile = new ZipFile("d:\\data\\myzipfile.zip");
ZipEntry zipEntry = zipFile.getEntry("fileName.txt");
InputStream inputStream = zipFile.getInputStream(zipEntry);
Since I can't create an instance that easily, I'm looking for an other way.
You are close to.
ZipInputStream.getNextEntry() does two things : it returns the next ZIP file entry but it also positions the current stream at the beginning of the current entry.
Reads the next ZIP file entry and positions the stream at the
beginning of the entry data.
So just invoke getNextEntry() and then you can use the ZipInputStream object which the read() method will read the content of the current entry.
you could write something like :
private void accessEachFileInZip (byte[] zipAsByteArray) throws IOException{
ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(zipAsByteArray));
while ((entry = zipStream.getNextEntry()) != null) {
// The zipStream state refers now to the stream of the current entry
...
}
zipStream.close();
}
I have trying to find out the solution for to unzip a particular file using java and Google app engine. I have tried using ZipInputStream but cant able to access the zip file that is uploaded in jsp. can any one help me to come out of this?
ServletFileUpload upload = new ServletFileUpload();
resp.setContentType("text/plain");
FileItemIterator iterator = upload.getItemIterator(req);
while (iterator.hasNext()) {
FileItemStream fileItemStream = iterator.next();
InputStream InputStream = fileItemStream.openStream();
if (!fileItemStream.isFormField()) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(InputStream));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
//code to access required file in the zip file
}
}
}
My guess would be that ZipInputStream requires stream that is seekable. The streams returned by servlets (and networking in general) aren't seekable.
Try reading the whole stream, then wrapping it in ByteArrayInputStream:
byte[] bytes = readBytes(fileItemStream.openStream());
InputStream bufferedStream = new ByteArrayInputStream(bytes);
public static byte[] readBytes(InputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int len;
byte[] data = new byte[100000];
while ((len = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, len);
}
buffer.flush();
return buffer.toByteArray();
}
I´m trying to implement some "over the air" update mechanism for OSGi bundles. For that, I need to be able to create a jar file from a String (basically the content of the jar file read by JarInputStream). The following example code should illustrate my needs:
//read bundle to be copied!
File originalFile = new File(
"/Users/stefan/Documents/Projects/OSGi/SimpleBundle_1.0.0.201404.jar");
JarInputStream fis = new JarInputStream(new FileInputStream(originalFile));
StringBuilder stringBuilder = new StringBuilder();
int ch;
while ((ch = fis.read()) != -1) {
stringBuilder.append((char) ch);
}
fis.close();
//Create content string
String content = stringBuilder.toString();
if (logger.isInfoEnabled()) {
logger.info(content);
}
//Init new jar input stream
JarInputStream jarInputStream = new JarInputStream(
new ByteArrayInputStream(content.getBytes()));
if (logger.isInfoEnabled()) {
logger.info("Save content to disc!");
}
File newFile = new File(
"/Users/stefan/Documents/Projects/OSGi/equinox/SimpleBundle_1.0.0.201404.jar");
//Init new jar output stream
JarOutputStream fos = new JarOutputStream(
new FileOutputStream(newFile));
if (!newFile.exists()) {
newFile.createNewFile();
}
int BUFFER_SIZE = 10240;
byte buffer[] = new byte[BUFFER_SIZE];
while (true) {
int nRead = jarInputStream.read(buffer, 0,
buffer.length);
if (nRead <= 0)
break;
fos.write(buffer, 0, nRead);
}
//Write content to new jar file.
fos.flush();
fos.close();
jarInputStream.close();
Unfortunately, the created jar file is empty and throws an "Invalid input file" error if I try to open it with JD-GUI. Is it possible to create a jar file from the String "content"?
Best regards and thank you very much
Stefan
Your jar is empty because you do not read anything from the JarInputStream. If you want to read JarInputStream, you should iterate its entries. If you want to change the Manifest, the first entry should be skipped, use the getManifest() of the jarInputStream and the constructor of the JarOutputStream, where Manifest can be specified. Based on your code (no manifest change but plain jar copy):
ZipEntry zipEntry = jarInputStream.getNextEntry();
while (zipEntry != null) {
fos.putNextEntry(zipEntry);
// Simple stream copy comes here
int BUFFER_SIZE = 10240;
byte buffer[] = new byte[BUFFER_SIZE];
int l = jarInputStream.read(buffer);
while(l >= 0) {
fos.write(buffer, 0, l);
l = jarInputStream.read(buffer);
}
zipEntry = jarInputStream.getNextEntry();
}
You only need this if you want to change the content (Manifest or entries) of the JAR file during the copy. Otherwise, simple InputStream and FileOutputStream will do the work (as Tim said).