Android Java:将文件从zip文件读入webview/string,为什么ZipInputStream会限制读取性能?
让我们先解释一下 我正在使用webView加载HTML应用程序。为了稍微保护源代码(脚本kiddie protection),我想从一个(受保护的)zip文件加载html代码。html代码已经打包、缩小、组合等,因此大小只有700kb(未打包)。这工作得很好,但有一个问题,它有点慢 在下面的示例中,我从zip读取html文件,并将结果放入字符串中。此字符串将用于使用以下代码将html代码加载到Android Java:将文件从zip文件读入webview/string,为什么ZipInputStream会限制读取性能?,java,android,zip,android-webview,unzip,Java,Android,Zip,Android Webview,Unzip,让我们先解释一下 我正在使用webView加载HTML应用程序。为了稍微保护源代码(脚本kiddie protection),我想从一个(受保护的)zip文件加载html代码。html代码已经打包、缩小、组合等,因此大小只有700kb(未打包)。这工作得很好,但有一个问题,它有点慢 在下面的示例中,我从zip读取html文件,并将结果放入字符串中。此字符串将用于使用以下代码将html代码加载到webview: this.webView.loadDataWithBaseURL("file:///a
webview
:
this.webView.loadDataWithBaseURL("file:///android_asset/", this.unzipStream(sFileName), "text/html", "UTF-8", "");
我使用了不同的解决方案来加快速度,并发现瓶颈在于从zip读取内容。我增加了读取缓冲区的块大小,但没有帮助,它从不读取完整的块大小。例如,当我使用4096字节(4kb)作为块大小时,它一次只能读取700到1100字节
问题:
- 如何强制读取函数使用指定的完整块大小
- 否则,还有其他更好的方法吗(例如,将其直接放入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 "";
}
公共字符串解压流(字符串sFileName)
{
最终整数块大小=4096;
//字符串sResult=“”;
long-iSize=0;
int-iReaded=0;
ByteArrayOutputStream sb=新建ByteArrayOutputStream();
试试{
InputStream=this.activity.getAssets().open(sFileName);
BufferedInputStream fin=新的BufferedInputStream(is);
ZipInputStream zin=新的ZipInputStream(fin);
紫丁香;
而((iSize==0)&&((ze=zin.getnextery())!=null)&&&!ze.isDirectory())
{
字节数据[]=新字节[块大小];
long iTotal=ze.getSize();
而((iReaded=zin.read(数据,0,块大小))>0&((iSize+=iReaded)0)
{
//Base64。
试一试{
使某人返回到字符串(“UTF-8”);
//sResult=新字符串(Base64.decode(sb.toString(“UTF-8”)、Base64.DEFAULT)、Charset.forName(“UTF-8”);
}
捕获(异常ee)
{
//sResult=“”;
}
}
返回“”;
}
也许还有另一种方法:
还找到了此java zipfile类。它使处理(受密码保护)zip文件更容易,但不包括将其解压缩为字符串的函数(至少我认为是这样)。在搜索时找不到任何内容。使用此类是否仍然可以这样做?尝试设置流的内部缓冲区大小:
BufferedInputStream fin = new BufferedInputStream(is, BLOCKSIZE);
ZipInputStream zin = new ZipInputStream(fin){ { buf = new byte[BLOCKSIZE]; } };
之后,可能标题可能是“ZipInputStream限制读取性能”或类似内容,因为其他类型的流不限制读取大小。当您想要获得4096字节时,您将获得4096字节。例如,使用文本文件对此进行了测试。我仍然不知道ZipInputStream限制读取性能的原因 我不确定是否有真正的性能提升(有时是,有时不是),但使用apache的“Commons IO”包中的now IOUtils-。这也简化了整个“操作” 我也见过一些使用通道的解决方案,但似乎只适用于文件流,因此无法使用它(或者无法找出如何将其应用于这种情况)。 另见:(见公认答案) 这是我制作的新版本(也将对象名称更改为有意义的名称):
使用而不是loadDataWithBaseUrl可能会提高性能。这不会解决块大小问题,但会允许WebKit在完成整个解压缩之前开始解析内容 您使用它的方式是:
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);
}
您好,谢谢您的回答,但没有加快任何速度。看起来很有趣,我们将很快尝试。另外,请查看marcin.kosiba的解决方案/答案,将两者结合起来。
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);
}