Android: read a GZIP file in the ASSETS folder
Asked Answered
S

6

5

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

Subcontinent answered 2/3, 2010 at 15:18 Comment(3)
Have you checked your file sizes? Since APK files are ZIP archives, if that resource gets compressed anyway, perhaps there is no value in GZIPping it.Hawkie
Echoing commonsware, I've found that gzipping assets has absolutely no effect on apk size since apk's are already compressed. Still, an interesting question why this doesn't work (as I've gotten such a scenario to function before, during my tests).Simarouba
int size = fIn.available(); <- java documentation says: Returns 0 after EOF has reached, otherwise always return 1.Skein
M
4

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.

Massie answered 10/8, 2010 at 8:18 Comment(2)
Actually, it doesn't decompress the file; it just strips off the .gz extension. You still would need to wrap the input stream in a GZIPInputStream to read it.Valency
Still happens on newest Android Studio.. :PSpheno
S
3
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

Skein answered 7/3, 2010 at 19:21 Comment(0)
S
2

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.

Scalade answered 7/3, 2010 at 19:17 Comment(0)
H
1

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.

Hombre answered 8/11, 2016 at 21:5 Comment(0)
S
0

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.

Simarouba answered 2/3, 2010 at 15:55 Comment(0)
M
0

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));
Mint answered 2/3, 2010 at 16:26 Comment(2)
I keep getting a FileNotFoundException which is ridiculus because the Resources know the file is there is R.raw.myfileSubcontinent
hmmm, that is an odd problem. It's a shot in the dark but maybe try refreshing your project in eclipse and recompiling as described on #2323320Mint

© 2022 - 2024 — McMap. All rights reserved.