is there any way how to open zip file and access it as it was unzipped in Android? I have zip file with data, which I need to be accessed by application and I don't want to unzip it to some folder and open it from there. So I want data access directly from zip file without unzipping it. I am now trying to use ZipFile, but I haven't found any usage, which might be usefull for me. Is this approach even possible?
Thanks
This is the code I've been using to 'unzip on the fly' and create drawables.
private void createBitmapDrawables() throws IOException {
// TODO Auto-generated method stub
InputStream is = getResources().getAssets().open("images.zip");
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
try {
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
String file = ze.getName();
byte[] bytes = baos.toByteArray();
drawable = createBitmapDrawable(bytes, file);
}
} finally {
zis.close();
}
}
Pretty much from the Android Dev site.
Hope it helps.
Well as every file, in order to use its content you have to open and read it in memory and typically at this purpose you use an InputStream. In this case you have to read an entry of a zip file so you can iterate trough the zip entry and when you find the entry you are looking for you can obtain a ZipInputStream for it and read like a normal file
Related
I have a file located at /res/introduced.xml. I know that I can access it in two ways:
1) the R.introduced resource
2) some absolute/relative URI
I'm trying to create a File object in order to pass it to a particular class. How do I do that?
This is what I ended up doing:
try{
InputStream inputStream = getResources().openRawResource(R.raw.some_file);
File tempFile = File.createTempFile("pre", "suf");
copyFile(inputStream, new FileOutputStream(tempFile));
// Now some_file is tempFile .. do what you like
} catch (IOException e) {
throw new RuntimeException("Can't create temp file ", e);
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
some absolute/relative URI
Very few things in Android support that.
I'm trying to create a File object in order to pass it to a particular class. How do I do that?
You don't. A resource does not exist as a file on the filesystem of the Android device. Modify the class to not require a file, but instead take the resource ID, or an XmlResourceParser.
To unzip zip file I've used classes from package java.util.zip* by refering this and it works correctly however to unzip a file of 40MB it takes 59 seconds. When I tried same zip file on iPhone project (we are developing app for both platforms - Android & iPone & that have functionality to unzip zip file & save unzipped content to SDCARD-Android or document directory - iPhone ), it takes only 14 seconds. The iphone app uses ziparchive.
So my question are:
1.From above experiment it clears that unzipping & file write operation to SDCARD in Java consumes more time as compared to iPhone app, so I decided to use C/C++ level unzipping & file write operation using NDK.
Is this right choice ?
2.I have searched on google, stackoverflow & some suggested to use minizip but there no sufficient help on how to use minizip in android. Is anyboday have tried minizip for android ?
3.I also tried NDK development for libz to achieve my goal, as Libz is added in NDK but not getting how to use it. Is anybody tried libz in NDK?
4.Is there any other Framework in Java or C/C++ that unzip large zip file & write them to SDCARD in less time ?
Please help me.
Here is my Java Unzip Code :
public String unzip() {
String result;
try {
FileInputStream fin = new FileInputStream(this.filePath);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.v("Unzip", "Unzipping " + ze.getName());
if (ze.isDirectory()) {
_dirChecker(ze.getName());
} else {
// Read 16 k at a time
byte[] buffer = new byte[16*1024];
int read;
FileOutputStream fout = new FileOutputStream(this.location+ "/" + ze.getName());
while ((read = zin.read(buffer)) != -1)
{
fout.write(buffer, 0, read);
}
zin.closeEntry();
fout.close();
}
}
zin.close();
result = "success";
} catch (Exception e) {
Log.e("unzip", "unzip", e);
result = "failure";
}
return result;
}
Why don't you try this code.It works awesome
String zipname = "data.zip";
FileInputStream fis = new FileInputStream(zipname);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
System.out.println("Unzipping: " + entry.getName());
int size;
byte[] buffer = new byte[2048];
FileOutputStream fos = new FileOutputStream(entry.getName());
BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length);
while ((size = zis.read(buffer, 0, buffer.length)) != -1) {
bos.write(buffer, 0, size);
}
bos.flush();
bos.close();
}
zis.close();
fis.close();
}
All of the unzip code eventually ends up in zlib. There is no Java implementation of "deflate" compression in Android core libs.
The only reason java.util.Zip should be slower than a "native" unzip is if the file I/O is done badly, e.g. something is using really small buffers. Looking at the code linked from the question, this is exactly what's happening -- it's operating on individual bytes.
One of the comments on the solution provided a patch that uses a 4K buffer. Drop that in and see what happens to your performance.
Try to just write 40Mb file to SDCard and measure time spent.
(Almost) all free (or even paid) implementations of zip archive support libraries are based on the same zlib code, which takes most processing speed during the unzipping. Java code should be much slower than native one, so I'd suggest to try NDK unzipping. Also, trying to unzip archive with zero compression level will give you a guess how much time unzipping code takes and how much time is spend on just data copying.
public boolean unzip(String zipfilepath, String destinationdir) {
try {
FileInputStream fis = new FileInputStream(zipfilepath);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
System.out.println("Unzipping: " + entry.getName());
int size;
byte[] buffer = new byte[2048];
FileOutputStream fos = new FileOutputStream(destinationdir+ "/" + entry.getName());
BufferedOutputStream bos = new BufferedOutputStream(fos, buffer.length);
while ((size = zis.read(buffer, 0, buffer.length)) != -1) {
bos.write(buffer, 0, size);
}
bos.flush();
bos.close();
}
zis.close();
fis.close();
return true;
}catch(Exception e){
return false;
}
}
String zipfilepath = context.getFilesDir().getPath()+"/"+myfile.zip;
String destinationdir = context.getFilesDir().getPath();
unzip(zipfilepath, destinationdir);
I'm reading files from a ZIP file that's located in my Android assets folder using ZipInputStream: it works, but it's really slow, as it has to read it sequentially using getNextEntry(), and there are quite a lot of files.
If I copy the ZIP file onto the SD card, reading is really fast when using ZipFile.getEntry, but I didn't find a way to use ZipFile with the asset file!
Is there any way to access the ZIP in the asset folder in a speedy way? Or do I really have to copy the ZIP to the SD card?
(BTW, in case anybody wonders why I'm doing this: the app is larger than 50 MB, so in order to get it in the Play Store I have to use Expansion APKs; however, as this app should also be put into the Amazon App Store, I have to use another version for this, as Amazon doesn't support Expansion APKs, naturally... I thought that accessing a ZIP file at two different locations would be an easy way to handle this, but alas...)
This works for me:
private void loadzip(String folder, InputStream inputStream) throws IOException
{
ZipInputStream zipIs = new ZipInputStream(inputStream);
ZipEntry ze = null;
while ((ze = zipIs.getNextEntry()) != null) {
FileOutputStream fout = new FileOutputStream(folder +"/"+ ze.getName());
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zipIs.closeEntry();
fout.close();
}
zipIs.close();
}
You can store the uncompressed files directly in assets (i.e. unpack the zip into assets/ folder). This way, you can access the files directly and they will be compressed anyway when you build the APK.
You can create a ZipInputStream in the following way :
ZipInputStream zipIs = new ZipInputStream(context.getResources().openRawResource(your.package.com.R.raw.filename));
ZipEntry ze = null;
while ((ze = zipIs.getNextEntry()) != null) {
FileOutputStream fout = new FileOutputStream(FOLDER_NAME +"/"+ ze.getName());
byte[] buffer = new byte[1024];
int length = 0;
while ((length = zipIs.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zipIs .closeEntry();
fout.close();
}
zipIs .close();
I have a text file in the assets folder that I need to turn into a File object (not into InputStream). When I tried this, I got "no such file" exception:
String path = "file:///android_asset/datafile.txt";
URL url = new URL(path);
File file = new File(url.toURI()); // Get exception here
Can I modify this to get it to work?
By the way, I sort of tried to "code by example" looking at the following piece of code elsewhere in my project that references an HTML file in the assets folder
public static Dialog doDialog(final Context context) {
WebView wv = new WebView(context);
wv.loadUrl("file:///android_asset/help/index.html");
I do admit that I don't fully understand the above mechanism so it's possible that what I am trying to do can't work.
Thx!
You cannot get a File object directly from an asset, because the asset is not stored as a file. You will need to copy the asset to a file, then get a File object on your copy.
You cannot get a File object directly from an asset.
First, get an inputStream from your asset using for example AssetManager#open
Then copy the inputStream :
public static void writeBytesToFile(InputStream is, File file) throws IOException{
FileOutputStream fos = null;
try {
byte[] data = new byte[2048];
int nbread = 0;
fos = new FileOutputStream(file);
while((nbread=is.read(data))>-1){
fos.write(data,0,nbread);
}
}
catch (Exception ex) {
logger.error("Exception",ex);
}
finally{
if (fos!=null){
fos.close();
}
}
}
Contrary to what others say, you can obtain a File object from an asset as follows:
File myAsset = new File("android.resource://com.mycompany.app/assets/my-asset.txt");
This function missing in code. #wadali
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}
Source: https://stackoverflow.com/a/4530294/4933464
How can you read GZIP file in Android located in the "ASSETS" (or resources/raw) folder?
I have tried the following code, but my stream size is always 1.
GZIPInputStream fIn = new GZIPInputStream(mContext.getResources().openRawResource(R.raw.myfilegz));
int size = fIn.available();
for some reason the size is always 1. But if Idon't GZIP the file, it works fine.
NOTE:
Using Android 1.5
I met the same problem when reading a gz file from assets folder.
It's caused by the file name of the gz file. Just renaming yourfile.gz to other name like yourfile.bin. It seems Android build system would decompress a file automatically if it thought it's a gz.
public class ResLoader {
/**
* #param res
* #throws IOException
* #throws FileNotFoundException
* #throws IOException
*/
static void unpackResources() throws FileNotFoundException, IOException {
final int BUFFER = 8192;
android.content.res.Resources t = TestingE3d.mContext.getResources();
InputStream fis = t.openRawResource(R.raw.resources);
if (fis == null)
return;
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis,
BUFFER));
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
int count;
FileOutputStream fos = TestingE3d.mContext.openFileOutput(entry
.getName(), 0);
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
byte data[] = new byte[BUFFER];
while ((count = zin.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
// Log.v("NOTAG", "writing "+count + " to "+entry.getName());
}
dest.flush();
dest.close();
}
zin.close();
}
}
R.raw.resources is a zip file - this class will decompress all files in that zip to your local folder.
I use this for NDK.
you can access your fils from ndk through:
/data/data//files/
package = package where ResLoader resides
filename = one of files that is in raw/resources.zip
this is the documented behavior of InflaterInputStream.available:
http://java.sun.com/javase/6/docs/api/java/util/zip/InflaterInputStream.html#available()
Returns 0 after EOF has been reached, otherwise always return 1.
abusing available is a common mistake --- in no case can you assume that it tells you the length of a file (though it sometimes happens to do so, as you've noticed). you want to keep calling read(byte[], int, int) until it returns 0. if you want the length to allocate a byte[] up front, you probably want to create a ByteArrayOutputStream and write to that each time you read, and then get a byte[] from that when you exit the loop. this works for all InputStreams in all cases.
It seems that the build system treats .gz files as a special case, even when it's included as a raw resource. Rename the .gz file to have a different extension, say .raw or .bin .
Valid at least for Android Studio 2.2 . I can't find any docs to confirm this is expected behaviour or, better, how to prevent it, but changing the extension at least works around the problem.
What happens if you use AssetManager instead of Resources? Example:
InputStream is = mContext.getAssets().open("myfilegz");
GZIPInputStream fIn = new GZIPINputStream(is);
Internally, Resources is just calling AssetManager; I wonder if somewhere along the way it musses things up.
Try looking at the source for Translate from apps-for-android open source project and see if that helps at all.
They use GZIPInputStream on a raw file in their selectRandomWord() function [line 326] (source pasted below)
public void selectRandomWord() {
BufferedReader fr = null;
try {
GZIPInputStream is =
new GZIPInputStream(getResources().openRawResource(R.raw.dictionary));