Unzipping Files with a large amount of small Files inside - java

I have a lot of zips with a large amount of Files which i have to unzip to the SD-Card.
Currently I am using the util.zip Package with Zipentry for each File inside the zips. This works fine but is very slow.
So I wonder if there is a lib which can handle those Files faster than the normal zip of Java/Android.
Edit: The zips are archives which are about 5 to 10MB large and contain about 50 to 100 jpg-Files whiche are each part of a picture. I need to extract all zips to a specific folder.
Slow means that the same files are extracted on an IPhone in fraction of the time.
Edit 2 the code:
ZipInputStream zin = new ZipInputStream(fd);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
System.out.println("Unzipping " + ze.getName());
if (ze.isDirectory()) {
File f = new File(targetFilePath + ze.getName());
if (!f.isDirectory()) {
f.mkdirs();
}
} else {
int size;
byte[] buffer = new byte[2048];
FileOutputStream outStream = new FileOutputStream(targetFilePath + ze.getName() + ".tile");
BufferedOutputStream bufferOut = new BufferedOutputStream(outStream, buffer.length);
while ((size = zin.read(buffer, 0, buffer.length)) != -1) {
bufferOut.write(buffer, 0, size);
}
bufferOut.flush();
bufferOut.close();
}
}
zin.close();

The best case you could do is go NDK way. AFAIK, Google even provides supported headers/API in NDK on zlib.

Related

Android: Get number of files in zip (with Storage Volume/Storage Access Framework)

I'm using the Storage Volume to unzip a zip file on the SD card of my Android 7.0 phone to a folder on the SD card:
InputStream is = getContentResolver().openInputStream(myZipFile.getUri());
BufferedInputStream bis = new BufferedInputStream(is);
ZipInputStream zis = new ZipInputStream(bis);
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) { ... }
To show the progress in a dialog I need the total amount of elements in the zip file. How do you do this with the Storage Volume/StorageAccesFramework?
You can't do it this way because you don't get the actual paths with SV/SAF:
ZipFile zip = new ZipFile(pathToZipFile);
int size = zip.size();
... and iterating over the whole file to count the number of files before you iterate over it again to unzip the file is slow:
while ((zipEntry = zis.getNextEntry()) != null) {
size++;
}

Why ZipEntry fails to work in Jelly Bean

I have a ZIP file of 140 MB containing about 40 thousand MP3 files. I use the following code to play a certain file inside the ZIP file without decompressing it:
String fullPath = Environment.getExternalStorageDirectory().getPath() + "_audio_.mp3";
String path = Environment.getExternalStorageDirectory().getPath() + "mySoundFolder";
try {
ZipFile zip = new ZipFile(path + "myFile.zip");
Enumeration zipEntries = zip.entries();
ZipEntry entry = zip.getEntry("myFile" + "/" + currentWord + ".mp3");
if (entry != null) {
Log.i(MAIN_TAG, "entry found: " + entry.getName());
InputStream in = zip.getInputStream(entry);
File f = new File(fullPath);
FileOutputStream out = new FileOutputStream(f);
IOUtils.copy(in, out);
byte buffer[] = new byte[4096];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
if (f.exists())
{
Log.i(MAIN_TAG,"Audio file found!");
final MediaPlayer mp = new MediaPlayer();
mp.setDataSource(fullPath);
mp.prepare();
mp.setOnBufferingUpdateListener(null);
mp.setLooping(false);
mp.setOnPreparedListener(new OnPreparedListener()
{ public void onPrepared(MediaPlayer arg0)
{
mp.start();
Log.i(MAIN_TAG,"Pronunciation finished!");
}});
}
else
{
Log.i(MAIN_TAG,"File doesn't exist!!");
}
}
else {
// no such entry in the zip
Log.i(MAIN_TAG, "no such entry in the zip");
}
}
catch (IOException e) {
e.printStackTrace();
Log.i(MAIN_TAG,"IOException reading zip file");
}
}
There are two strange things with this code:
It works flawlessly in Android 2.2 but fails in Android 4.0.3. In 2.2, it finds and plays the MP3 file as I expect, but in 4.0.3, it keeps saying it cannot find the entry in the ZIP file ("no such entry in the zip").
If I reduce the number of MP3 files down to about 100 files, then in Android 4.0.3, it finds and plays the selected MP3 files as it should do.
Can you guys please help me to figure out what the problem is?
Thanks a lot in advance.
In the end, I have a workaround for this problem. I split my zip file into two files, with each containing about 20k entries. Voila, it works like a charm again.
I've heard of Java's problem with reading entries in zip files of more than 64k entries. What I have no idea why is my file has only about 40k entries but it faces the problem as well.

How to create ZIP files using list of Input streams?

In my case I have to download images from the resources folder in my web app. Right now I am using the following code to download images through URL.
url = new URL(properties.getOesServerURL() + "//resources//WebFiles//images//" + imgPath);
filename = url.getFile();
is = url.openStream();
os = new FileOutputStream(sClientPhysicalPath + "//resources//WebFiles//images//" + imgPath);
b = new byte[2048];
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
But I want a single operation to read all images at once and create a zip file for this.
I don't know so much about the use of sequence input streams and zip input streams so if it is possible through these, please let me know.
The only way I can see you being able to do this is something like the following:
try {
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream("C:/archive.zip"));
//GetImgURLs() is however you get your image URLs
for(URL imgURL : GetImgURLs()) {
is = imgURL.openStream();
zip.putNextEntry(new ZipEntry(imgURL.getFile()));
int length;
byte[] b = new byte[2048];
while((length = is.read(b)) > 0) {
zip.write(b, 0, length);
}
zip.closeEntry();
is.close();
}
zip.close();
}
Ref: ZipOutputStream Example
The url should return zip file. Else you have to take one by one and create a zip using your program

uncompress files from a tar using apache commons - prob is duplicate entry

Scenario: Uncompress a tar file using Apache commons.
Problem: The tar i am using is a build tar which gets deployed into a web server. This tar contains duplicate entries like below.
appender_class.xml
APPENDER_CLASS.xml
when extracting using the below code only appender_class.xml is extracted but i want both the files how can i do that ? Renaming in fly is fine but how can i accomplish that?
public static void untar(File[] files) throws Exception {
String path = files[0].toString();
File tarPath = new File(path);
TarEntry entry;
TarInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = new TarInputStream(new FileInputStream(tarPath));
while (null != (entry = inputStream.getNextEntry())) {
int bytesRead;
System.out.println("tarpath:" + tarPath.getName());
System.out.println("Entry:" + entry.getName());
String pathWithoutName = path.substring(0, path.indexOf(tarPath.getName()));
System.out.println("pathname:" + pathWithoutName);
if (entry.isDirectory()) {
File directory = new File(pathWithoutName + entry.getName());
directory.mkdir();
continue;
}
byte[] buffer = new byte[1024];
outputStream = new FileOutputStream(pathWithoutName + entry.getName());
while ((bytesRead = inputStream.read(buffer, 0, 1024)) > -1) {
outputStream.write(buffer, 0, bytesRead);
}
System.out.println("Extracted " + entry.getName());
}
}
Try opening your FileOutputstream like this instead:
File outputFile = new File(pathWithoutName + entry.getName());
for(int i = 2; outputFile.exists(); i++) {
outputFile = new File(pathWithoutName + entry.getName() + i);
}
outputStream = new FileOutputStream(outputFile);
It should generate a file called APPENDER_CLASS.xml2 if it encounters a previously created file called APPENDER_CLASS.xml. If a APPENDER_CLASS.xml2 exists it will create a APPENDER_CLASS.xml3, ad infinitum.
File.exists() takes case sensitivity into account (windows filenames are case insensitive, whereas unix, linux and mac are case sensitive). Thus with the above code on case insensitive filesystems the file would be renamed and on case sensitive filesystems the file would not be renamed.

How to use java.util.zip for epub

I have to edit the html files of epubs programmatically so what I did was to unzip the .epub and create a parser to make the necessary edits for the html files. However, when I convert them back into an .epub using my code, EpubChecker shows that:
Error: Required META-INF/container.xml resource is missing
When I uncompressed my edited .epub, the container.xml is present and is not missing.
I understand that the mimetype and META-INF has to be zipped first. Here is my code to convert the files back to epub:
FileOutputStream fos = new FileOutputStream(zipFile);
ZipOutputStream zos = new ZipOutputStream(fos);
System.out.println("Output to Zip : " + zipFile);
writeMimeType(zos);
ZipEntry container = new ZipEntry("META-INF\\container.xml");
zos.putNextEntry(container);
FileInputStream inMime2 = new FileInputStream(SOURCE_FOLDER + File.separator + "META-INF\\container.xml");
int len2;
while((len2 = inMime2.read(buffer)) > 0){
zos.write(buffer, 0, len2);
}
inMime2.close();
for(String file : this.fileList){
if(!file.toString().equals("mimetype") && !file.toString().equals("META-INF\\container.xml")){
System.out.println("File Added : " + file);
ZipEntry ze= new ZipEntry(file);
zos.putNextEntry(ze);
FileInputStream in =
new FileInputStream(SOURCE_FOLDER + File.separator + file);
int len;
while ((len = in.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
in.close();
}
}
zos.closeEntry();
zos.close();
When I manually zip the directory using WinRar, no errors are seen and it works properly. I don't know what I am doing wrong. Can somebody please help me?Thank you.
Looks like you're on Windows, so your FileInputStream(SOURCE_FOLDER + File.separator + "META-INF\\container.xml"); statement is correct for the OS, but I'd guess you need to change the other 2 strings to use the forward slash for the zipentry path.
ZipEntry container = new ZipEntry("META-INF\\container.xml");
try instead as
ZipEntry container = new ZipEntry("META-INF/container.xml");
and change
if(!file.toString().equals("mimetype") && !file.toString().equals("META-INF\\container.xml")){
to
if(!file.toString().equals("mimetype") && !file.toString().equals("META-INF/container.xml")){
accordingly.
You may need to adjust your other ZipEntry's as well. From the ZIP spec (section "4.4.17 file name"):
All slashes MUST be forward slashes '/' as opposed to backwards
slashes '\'

Categories

Resources