Decompressing zip files with accents - java

I'm using a Java mechanism to extract zip files. The mechanism works fine if there is no files in it with accents on title. Since I'm from portugal, chars like ã, ç, õ, é, etc. are usually used in my language. If any of this chars are in the filename, an IO exception occurs.
while (zipFileEntries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) zipFileEntries.nextElement();
File destFile = new File(unzipDestinationDirectory, currentEntry);
File destinationParent = destFile.getParentFile();
// create the parent directory structure if needed
destinationParent.mkdirs();
// extract file if not a directory
if (!entry.isDirectory()) {
BufferedInputStream is =
new BufferedInputStream(zip_file.getInputStream(entry));
int currentByte;
byte data[] = new byte[BUFFER];
// write the current file to disk
FileOutputStream fos = new FileOutputStream(destFile);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
// read and write until last byte is encountered
while ((currentByte = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, currentByte);
}
dest.flush();
dest.close();
is.close();
}
It crashes on while((currentByte = is.read(data, 0, BUFFER)) != -1)
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:134)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at parsers.ZipParser.decompressZipFile(ZipParser.java:83)
at poc.MainPOC.main(MainPOC.java:61)
Are you aware of any workaround to deal with this problem? Can I change the filename of a file inside a zip without decompressing it?

Since Java 7, there is a way new construcor to ZipInputStreamto specify a charset to use for the filename. See the documentation here.
So you would create your ZipInputStream with something like :
ZipInputStream zis = new ZipInputStream(new FileInputStream("your zip file"), Charset.forName("Encoding here"));
See Charset to have a bit more informations about how to use it.
It will not change the way you are reading the file, so you will need another workaround to read the content. But for more information, see this answer Java zip character encoding, you can probably re-use some of the code.

I think you must set the encoding properly when you compress and decompress. Did you make it UTF-8 when you created the ZIP file? If not, I'd recommend trying it.

Related

SevenZFile - Apache Commons Compress 1.15, Uncompress

While Uncompressing .7z file, Empty folders are ignored, I want to consider Empty folders as well after uncompressing any .7z file.
My Code is as below
SevenZFile sevenZFile = new SevenZFile(new File(filename));
SevenZArchiveEntry entry;
while ((entry = sevenZFile.getNextEntry()) != null){
if (entry.isDirectory()){
continue;
}
File curfile = new File(DestinationPath,entry.getName());
File parent = curfile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
FileOutputStream out = new FileOutputStream(curfile);
byte[] content = new byte[(int) entry.getSize()];
sevenZFile.read(content, 0, content.length);
out.write(content);
out.close();
Your code seems working.
Probably the folder aren't in the "yourfile.7zip" from the beginning.
This is a common issue of 7zip and you have to update your 7zip version.
If the 7Zip contains proper arguments just use:
if (entry.isDirectory()){
new File(DestinationPath,entry.getName()).mkdir();
continue;
}
Since:
A file output stream is an output stream for writing data to a File or
to a FileDescriptor.
That is the proper method to accomplish the task because there's no folder implementation by native library vendor.

Replacing a Zip file without unzipping in Java

I have a zip file and I want to replace one file inside it with another file. So do not need to delete a zip entry just replace the file for the zip entry with another.
Here is what I have tried.
public void replaceConfigurationFile(ZipFile zipFile, ZipOutputStream zos, String pathToNewFile, String configFileToReplaced)
throws IOException {
String zipEntryName;
for(Enumeration<?> e = zipFile.entries(); e.hasMoreElements(); ) {
ZipEntry entryIn = (ZipEntry) e.nextElement();
zipEntryName = entryIn.getName();
if(zipEntryName.endsWith(configFileToReplaced)) {
FileInputStream fis = new FileInputStream(pathToNewFile);
ZipEntry zipEntry = new ZipEntry(zipEntryName);
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();
} else {
zos.putNextEntry(entryIn);
InputStream is = zipFile.getInputStream(entryIn);
byte [] buf = new byte[1024];
int len;
while((len = (is.read(buf))) > 0) {
zos.write(buf, 0, len);
}
zos.closeEntry();
}
} // enf of for
}
I have a file zip Entry named :
WEB-INF/classes/config/app-dev.yml
and I have a file at location d drive at location
D:/app-dev.yml
I am able to copy the file in to a different zip file by replacing the file i want to replace . But that is really not needed (to create a different file).
So what should I do to just replace the file with my custom file.
I have searched different posts in Stackoverflow, but unable to find what i need. I read that zip entry cannot be deleted but what about replacing it ? Please help
Your problem is that the new file might be larger than the old file - or smaller! You need to do exactly what you did to allow for the change. The probability that the new file, ZIPped, is exactly the same size as the previous one is virtually nil.
The standard Java ZIP file libraries do not allow you to update an existing ZIP file. You need to use a third party library. A Google search should find you a number of alternatives.
But you need to be aware of a couple of things:
If your application ... or system ... crashes while updating the ZIP file, the file may be corrupted.
When a ZIP file is updated, the replacement version of the file will be appended to the ZIP. The old version of the will still be in the ZIP ... but not in the ZIP file index. Hence updating a ZIP file (without rewriting it) wastes disk space.

Improper zip entries when writing filename containing non-English characters even with Java 7

I am trying to develop code that can handle zipping files with non-English characters (Umlaut, Arabic etc) but the zipped file contains improper names. I am using java version 1.7.0_45 thus it shouldn't be due to the bug mentioned here.I am setting the charset to UTF-8 for the ZipOutputStream constructor and as per Javadocs it should work as per my requirements.
I am assured that the zip file is being written correctly as an attempt to read entries from the file gives proper filenames (as expected).
However, when I try to open/extract with either Ubuntu default ArchiveManager/Unzip tool, the filenames are messed up.
Here is my code :
private void convertFilesToZip(List<File> files) {
FileInputStream inputStream = null;
try {
byte[] buffer = new byte[1024];
FileOutputStream fileOutputStream = new FileOutputStream("zipFile.zip");
ZipOutputStream outputStream = new ZipOutputStream(fileOutputStream, Charset.forName("UTF-8"));
for (File file : files) {
inputStream = new FileInputStream(file);
String filename = file.getName();
System.out.println("Adding file : " + filename);
outputStream.putNextEntry(new ZipEntry(filename));
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
outputStream.closeEntry();
}
if(inputStream != null) inputStream.close();
outputStream.close();
System.out.println("Zip created successfully");
System.out.println("=======================================================");
System.out.println("Reading zip Entries");
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(new File("zipFile.zip")), Charset.forName("UTF-8"));
ZipEntry zipEntry;
while((zipEntry=zipInputStream.getNextEntry())!=null){
System.out.println(zipEntry.getName());
zipInputStream.closeEntry();
}
zipInputStream.close();
} catch (IOException exception) {
exception.printStackTrace();
}
}
the output for the files is as follows:
Adding file : umlaut_ḧ.txt
Adding file : ذ ر ز س ش ص ض.txt
Adding file : äǟc̈ḧös̈ ẗǚẍŸ_uploadFile4.txt
Adding file : pingüino.txt
Adding file : ÄÖÜäöüß- Español deEspaña.ppt
Zip created successfully
=======================================================
Reading zip Entries
umlaut_ḧ.txt
ذ ر ز س ش ص ض.txt
äǟc̈ḧös̈ ẗǚẍŸ_uploadFile4.txt
pingüino.txt
ÄÖÜäöüß- Español deEspaña.ppt
Has anyone successfully implemented what I wish to achieve here.
Can someone point me to what I may have missed or have been doing wrong.I did all the google I could and even tried Apache Commons Compress but still no luck.
It's mentioned in the bug report that the bug is resolved in Java 7, then why is the code not working.
[Update]
I finally figured out that the problem is not in the code but is in fact with the default ArchiveManager of Ubuntu. It doesn't recognizes/extracts the contents properly. When the same file is opened/extracted by the windows zip handler, it works flawlessly.
Additionally, the commons-compress supports a bunch of other formats too apart from the zip,gzip supported by Java.
http://commons.apache.org/proper/commons-compress/index.html

Java most efficient way to retrieve something out of the middle of a ZIP

I am seeking for most efficient way (in terms of speed) to retrieve some file out of the middle of a ZIP file.
e.g. I have ZIP file, which includes 700 folders (tagged 1 to 700). Each folder equals picture and mp3 file. There is special folder called Info, which contains XML file. Problem is, I need to iterate through this ZIP file to find XML file and then I am displaying images from desired folders. I am using ZipFile approach (thus I am iterating through whole ZIP file, even if I want folder 666, I need to go through 665 items in ZIP file) -> selecting from ZIP file is extremely slow.
I would like to ask you, If you have faced similar issue, how have you solved this? Is there any approach in Java, which turns my ZIP file into virtual folder to browse it much more quicker? Is there any external library, which is the most efficient in terms of time?
Source Code snippet:
try {
FileInputStream fin = new FileInputStream(
"sdcard/external_sd/mtp_data/poi_data/data.zip");
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
// Log.d("ZE", ze.getName());
if (ze.getName().startsWith("body/665/")) {
// Log.d("FILE F", "soubor: "+ze.getName());
if (ze.getName().endsWith(".jpg")
|| ze.getName().endsWith(".JPG")) {
Log.d("OBR", "picture: " + ze.getName());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zin.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
byte[] bytes = baos.toByteArray();
bmp = BitmapFactory.decodeByteArray(bytes, 0,
bytes.length);
photoField.add(bmp);
i++;
}
}
}
}
The ZipFile.getEntry() and ZipFile.getInputStream() methods can be used to access a specific file in a ZIP archive. For example:
ZipFile file = ...
ZipEntry entry = file.getEntry("folder1/picture.jpg");
InputStream in = file.getInputStream(entry);

How to convert a InputStream to ZIP format?

I am having a InputStream Object which is actually a zip file. I want to change it back to zip file and save it. I am using DWR's FileTransfer class object to receive the uploaded data from client.
FileTransfer have 3 methods, getInputStream() is one of them. It returns InputStream from FileTransfer object.
In my case, fileTransfer object holds zip file and as well as InputStream object too.
I have done, lot of searches in google. But i am not able to find one example, that illustrates InputStream to zip conversion.
Update
String zipName = file.getName();
String zipType = file.getMimeType();
InputStream zipStream = file.getInputStream();
ZipInputStream zis = new ZipInputStream(zipStream);
System.out.println("File Name: "+zipName+"\n"+"File Type: "+zipType);
int c;
File f2 = new File(DATA_STORE_LOC+dat+".zip");
path.setPath2(DATA_STORE_LOC+dat+".zip");
FileOutputStream fos = new FileOutputStream(f2);
ZipOutputStream zos = new ZipOutputStream(fos);
c = zis.read();
System.out.println(c);
while ((c = zis.read(BUFFER)) != -1) {
zos.write(BUFFER, 0, c);
}
zos.close();
zis.close();
I tried this code, by thought of a typical file copy program. I know it is false, just tried. It gives me java.util.zip.ZipException: ZIP file must have at least one entry.
Any suggestion would be really appreciative!!!!!
See the examples java2s, input and output. If you have more questions feel free to ask them :)
For clarity, in this input example you should do something like:
// FileInputStream fin = new FileInputStream(args[i]);
ZipInputStream zin = new ZipInputStream(ft.getInputStream());
As Don Roby correctly said, if you just want to copy you need not know the file structure and you could use for example static IOUtils.copy(in, out) to copy the file.
Further, if you do wish to extract the ZIP file contents, you should not plainly copy bytes. The ZIP file has a structure, and you extract Entries from the ZIP file, and not just bytes (see the example). Every Entry is a (compressed) file (or the data thereof) with the original name:
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
System.out.println("Unzipping " + ze.getName());
FileOutputStream fout = new FileOutputStream(ze.getName());
for (int c = zin.read(); c != -1; c = zin.read()) {
...
Please note the javadoc of getNextEntry():
Reads the next ZIP file entry and positions the stream at the beginning of the entry data.
This positioning is crucial to get to the zipped file contents, and not the metadata.
And I do believe that you accidentally remove the first int:
c = zis.read(); // removing the first
while ((c = zis.read(BUFFER)) != -1) { // so you start with the second?
I believe you mix 2 idioms:
c = zis.read();
while(c != -1) {
...
c = zis.read();
}
and:
int c;
while ((c = zis.read(BUFFER)) != -1) { // so you start with the second?
...
}
I think you can see the difference :)
If your input is a an InputStream from a zip file and your desired output is still a zip file with the same contents, you're just doing a file copy operation and shouldn't have to worry about zip at all. You just need to read from the InputStream and write to a FileOutputStream, more or less as you're doing, but without worrying about wrapping either stream in a zip-aware stream.
ZipInputStream is useful if you have to extract the contents of the zip file as separate files, i.e., to programmatically unzip. And on the other side, ZipOutputStream is used if your have the contents and need to combine them into a zip file.

Categories