2

this is my first question, although I've already used so many tips from Stack Overflow. But for this situation I haven't found a solution yet.

Here's the situation: I have a zipped file and I want to read a specific file and put its content into a String variable, that will be returned and put into a TextView in Android. I don't want the file to be written to sdcard, I just want to perform a memory operation.

For example, inside db.zip I have a file named packed.txt, which content is "Stack á é ç". The returned String in my method shows "83 116 97 99 107 32 195 161 32 (...)" which are the UTF-8 values for the characters. I tried so far converting'em to a human-readble form, but no success. Tried InputStreamReader but I couldn't make a correct use of it. My source-code is below.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.util.Log;

/** 
 * 
 * @author jon 
 */ 
public class Decompress { 
  private String _zipFile; 
  private String _location;

  public Decompress(String zipFile, String location) { 
    _zipFile = zipFile; 
    _location = location; 

    _dirChecker(""); 
  } 

  public String unzip(String desiredFile) { 

      String strUnzipped = ""; 

      try  { 
      FileInputStream fin = new FileInputStream(_zipFile); 
      ZipInputStream zin = new ZipInputStream(fin); 
      ZipEntry ze = null; 
      while ((ze = zin.getNextEntry()) != null) { 
        Log.v("Decompress", "Unzipping " + ze.getName()); 

        if(ze.isDirectory()) { 
          _dirChecker(ze.getName()); 
        } else { 

          //FileOutputStream fout = new FileOutputStream(_location + ze.getName());

            /**** Changes made below ****/  
              if (ze.getName().toString().equals(desiredFile)) {                  
                byte[] bytes = new byte[(int) ze.getSize()];
            if (zin.read(bytes, 0, bytes.length) == bytes.length) {
              strUnzipped = new String(bytes, "UTF-8");
            }
            else {
              strUnzipped = "Read error...";
            }

            /*** REMOVED
            if (ze.getName() == desiredFile) {
            for (int c = zin.read(); c != -1; c = zin.read()) {
              strUnzipped += c;
              //fout.write(c); 
            } */
          }

          zin.closeEntry(); 
          //fout.close(); 
        } 

      } 
      zin.close(); 
    } catch(Exception e) { 
      Log.e("Decompress", "unzip", e); 
    }

    return strUnzipped;

  } 

  private void _dirChecker(String dir) { 
    File f = new File(_location + dir); 

    if(!f.isDirectory()) { 
      f.mkdirs(); 
    } 
  } 
}
Daniel
  • 708
  • 1
  • 8
  • 18

3 Answers3

4

Sorry for my initial posting of this .... ran right over your paragraph stating you had tried this.

You can create the InputStreamReader with a charset of "UTF-8" which will automatically convert the input data into the correct characters for you.

while ((ze = zin.getNextEntry()) != null) { 
    Log.v("Decompress", "Unzipping " + ze.getName()); 
    if(ze.isDirectory()) { 
        _dirChecker(ze.getName()); 
    } else {
        if (ze.getName() == desiredFile) {
            byte[] bytes= new byte[ze.getSize()];
            zin.read(bytes, 0, bytes.length);
            strUnzipped= new String( bytes, "UTF-8" );
            /* Removing this as it is easier to just read all the bytes in at once
            InputStreamReader isr= new InputStreamReader(zin, "UTF-8");
            char c= 0;
            for (char c = isr.read(); c != -1; c = isr.read()) {
            strUnzipped += c;
            } 
            */
        }
        zin.closeEntry(); 
    }
} 

Please try the above and see how it works out.

Dave G
  • 9,639
  • 36
  • 41
  • Hi Dave, thanks for the answer. I tried it and Eclipse says "cannot convert from int to char" and it suggests the following correction: "for (char c = (char) isr.read(); c != -1; c = (char) isr.read()) {". But when compiled it crashes the emulator! – Daniel Jul 20 '11 at 17:45
  • Sorry I had forgotten that the read returns an "int". As for the crash, that's REALLY odd! I would try cleaning out your project (Projects > Clean) code base and restarting the emulator then re-deploy your application to the emulator. If this is still giving you problems, hit me up again with a comment. – Dave G Jul 20 '11 at 19:22
  • Actually I think I see the problem with my suggested read loop. Give me a minute to track down the correct way to do this. – Dave G Jul 20 '11 at 19:24
  • I made a change to the loop basically removing it. But this should work better. As a sanity check you may want to tweak the zin.read() line to check to make sure you've read the correct amount of bytes. – Dave G Jul 20 '11 at 19:32
  • It worked! Thanks for helping. In spite of I need to add a "(int)" in the line: byte[] bytes = new byte[(int) ze.getSize()];. Is that safe? I added a sanity check above, is that what you meant? – Daniel Jul 20 '11 at 21:49
  • I'm facing the byte array limit problem. It seems to be limited to 1024 items, however I'm dealing with text files up to 100 KB. Is there a way to solve this limitation? – Daniel Jul 20 '11 at 23:04
  • Well your array can be up to Integer.MAX_INT in length. What you're probably running into is a read buffer where it is only reading 1024 bytes at a time. This stackoverflow http://stackoverflow.com/questions/309424/in-java-how-do-a-read-convert-an-inputstream-in-to-a-string should give you a more elegant solution to the limited read problem. This is a common problem when reading from streams specifically network sockets. If you know the full length of the input, you have a boundary condition that works with the article I linked. – Dave G Jul 21 '11 at 01:49
  • This takes ages to process when loading a 1MB file from a ZIP for example. This is caused by the reallocation of the string strUnzipped when add a new string. Is there an other solution to this? – Codebeat Mar 07 '14 at 10:47
  • Warning: ZipEntry.getSize() may return -1 as the JavaDoc states. – Ridcully Apr 21 '15 at 13:05
2

Why not load them into a byte array and use new String(byte[]) or use the StringBuilder?

StringBuilder sb = new StringBuilder();
for (int c = zin.read(); c != -1; c = zin.read()) {
    sb.append((byte)c);
}
...
return sb.toString();
Luiz Cavalcanti
  • 243
  • 1
  • 6
0
...         
while ((ze = zis.getNextEntry()) != null) {
    if (ze.getName().equalsIgnoreCase(desiredFile)) {
        byte[] buffer = new byte[1024];
        String texto="";
        while (zis.read(buffer) > 0) {
            texto+=new String(buffer,"ISO-8859-1");
        }   
        break;
    }
}

return texto;

  • 1
    Can you please provide some extra details how the above snippet can help into solving the problem? – madlymad Nov 16 '19 at 14:37