首页 文章

Android Java:从zip文件读取文件到webview / string,为什么ZipInputStream会限制读取性能?

提问于
浏览
2

Let's explain it first

我正在使用webView加载HTML应用 . 为了保护源(脚本小子保护)我想从(受保护的)zip文件加载html代码 . html代码已经打包,缩小,组合等,所以大小只有700kb(解压缩) . 这很好用,但有一个问题,它有点慢 .

在下面的示例中,我从zip读取html文件并将结果放在一个字符串中 . 该字符串将用于通过使用以下代码将html代码加载到 webview

this.webView.loadDataWithBaseURL("file:///android_asset/", this.unzipStream(sFileName), "text/html", "UTF-8", "");

我已经使用不同的解决方案来加快速度并找出 bottleneck is at reading the contents from the zip. I increased the read buffer's blocksize but doesn't help, it never reads the full blocksize. 例如,当我使用4096字节(4kb)作为块大小时,它一次只能读取700到1100个字节 .

Question(s):

  • 如何强制read函数使用指定的完整块大小?

  • 否则,是否有另一种更好的方法(例如将其直接放入webview)?

这是我做的代码:

public String unzipStream( String sFileName ) 
    { 
        final int BLOCKSIZE = 4096;
        //String sResult = ""; 
        long iSize   = 0;
        int iReaded = 0;
        ByteArrayOutputStream sb = new ByteArrayOutputStream(); 

        try  { 
          InputStream is = this.activity.getAssets().open( sFileName );
          BufferedInputStream fin = new BufferedInputStream( is ); 
          ZipInputStream zin = new ZipInputStream(fin); 
          ZipEntry ze;

          while( (iSize == 0) && ((ze = zin.getNextEntry()) != null) && !ze.isDirectory() ) 
          {
               byte data[]  = new byte[BLOCKSIZE];
               long iTotal  = ze.getSize();

               while ((iReaded = zin.read(data,0,BLOCKSIZE)) > 0 && ((iSize+=iReaded) <= iTotal) ) 
               {   
                   sb.write(data,0,iReaded);
               }
               zin.closeEntry(); 
          } 

          zin.close(); 
        } 
        catch(Exception e) 
        { 
             System.out.println("Error unzip: "+e.getMessage());
             //sResult = "";
             iSize = 0;
        } 

        if( iSize > 0 )
        {
            //Base64.
            try {
                return sb.toString("UTF-8");
                //sResult = new String( Base64.decode(sb.toString("UTF-8"), Base64.DEFAULT), Charset.forName("UTF-8") );
            }
            catch(Exception ee)
            {
               //sResult = "";
            }
        }

        return "";
      }

Maybe another way to do it:

还发现了这个java zipfile类http://www.lingala.net/zip4j/ . 它使处理(密码保护)的zip文件更容易,但不包括一个函数(至少我认为是这样)将其解压缩为字符串 . 在搜索时找不到任何东西 . 这个课程无论如何都可能吗?

3 回答

  • 1

    之后, Headers 可能是“ZipInputStream限制读取性能”或类似的 Headers ,因为其他类型的流不限制读取大小 . 如果要获得4096个字节,则将获得4096个字节 . 例如,使用文本文件对此进行测试 . 我仍然不知道为什么ZipInputStream会限制读取性能 .

    我'm not really sure there is a real performance boost (sometimes it is and sometimes not), but using now IOUtils from apache' s 'Commons IO'包 - http://commons.apache.org/proper/commons-io/ . 这也简化了整个'operation' .

    我也看到了一些带有通道的解决方案,但似乎只能使用文件流,所以不能使用它(或者无法弄清楚如何将它应用于这种情况) . 另请参阅:Faster way of copying data in Java?(参见接受的答案) .

    这是我制作的新版本(将对象名称更改为有意义的名称):

    public String unzipStream( String sFileName ) 
    { 
        ByteArrayOutputStream oBaosBuffer = new ByteArrayOutputStream(); 
        try  
        { 
          ZipInputStream oZipStream = new ZipInputStream( this.activity.getAssets().open( sFileName ) ); 
          ZipEntry oZipEntry;
          long iSize = 0;
    
          while( (iSize == 0) && ((oZipEntry = oZipStream.getNextEntry()) != null) && !oZipEntry.isDirectory() ) 
          {
               iSize = IOUtils.copyLarge(oZipStream, oBaosBuffer);
               oZipStream.closeEntry(); 
          } 
    
          oZipStream.close(); 
    
          if( iSize > 0 )
          {
            return oBaosBuffer.toString("UTF-8");
            //sResult = new String( Base64.decode(sb.toString("UTF-8"), Base64.DEFAULT), Charset.forName("UTF-8") );
          }
        } 
        catch(Exception e) 
        { 
             System.out.println("Error unzip: "+e.getMessage());
        } 
    
        return null;
    }
    
  • 0

    使用shouldInterceptRequest而不是loadDataWithBaseUrl可能会获得较小的性能提升 . 那赢得了整个解压缩的全部内容 .

    你使用它的方式是:

    class MyWebViewClient extends WebViewClient {
    @Override
    public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
        // this method is *not* called on the UI thread, be careful to not touch UI classes.
        if (Uri.parse(url).getHost().equals(Uri.parse("file:///android_asset/..."))) {
            // This assumes you pass in the AssetManager to the MyWebViewClient constructor.
            InputStream is = assetManager.open(sFileName);
            ZipInputStream zipInputStream = new ZipInputStream(is); 
            return new WebResourceResponse("text/html", "UTF-8", zipInputStream);
        }
        return super.shouldInterceptRequest(view, url);
    }
    
  • 1

    尝试设置流的内部缓冲区大小:

    BufferedInputStream fin = new BufferedInputStream(is,  BLOCKSIZE); 
        ZipInputStream zin = new ZipInputStream(fin){ { buf = new byte[BLOCKSIZE]; }  };
    

相关问题