最近在pc中测试j2me gzip的效率:
碰到了如下异常: java.io.IOException: Unexpected end of ZLIB input stream at com.tinyline.util.GZIPInputStream.if(+39) at com.tinyline.util.GZIPInputStream.for(+48) at com.tinyline.util.GZIPInputStream.read(+27) at com.tinyline.util.GZIPInputStream.read(+8) ...... java.lang.NullPointerException
at java.io.OutputStream.write(+4) ..... 上网搜索找到如下文章,对我有所启示,毕竟按照它的改法,在pc中,在手机中都ok了。 见 : http://hi.baidu.com/bobylou/blog/item/1f8600e91de9ee3cb90e2de6.html [第一篇]: java.io.EOFException: Unexpected end of ZLIB 的临时解决方法 2007-12-01 04:09 bobrow小作,允许自由转帖,不过请注明作者和出处,谢谢。 在玩httpunit1.6时,捕获了“java.io.EOFException: Unexpected end of ZLIB”异常。
问题是这样的,com.meterware.httpunit.WebResponse类的readFromStream方法中有一段读取inputStream的代码: if (maxBytes > 0) { do { outputStream.write( buffer, 0, count ); maxBytes -= count; if (maxBytes <= 0) break; count = inputStream.read( buffer, 0, Math.min( maxBytes, buffer.length ) ); } while (count != -1); } 抛出异常的正是做红色标记的代码。由于抛出异常的前一个count值不是-1,所以执行了红色代码。跟踪进去,发现java.util.zip.InflaterInputStream类方法fill(): protected void fill() throws IOException { ensureOpen(); len = in.read(buf, 0, buf.length); if (len == -1) { throw new EOFException("Unexpected end of ZLIB input stream"); } inf.setInput(buf, 0, len); } 因len为-1所以抛出异常。 按照我自己的理解,len为-1之前count肯定也为-1。但是实际执行过程却是count不为-1(表示inputStream还有后续内容),但是len为-1(表示in没有后续内容了),这是矛盾的嘛。我还没深入查看inputStream是怎么转为fill()方法中in的。 知道问题大概所在,我采取了很没技术含量的方法:catch fill()方法抛出的IOException,然后在catch中把count置-1。代码如下:
if (maxBytes > 0) { do { outputStream.write( buffer, 0, count ); maxBytes -= count; if (maxBytes <= 0) break; try { count = inputStream.read( buffer, 0, Math.min( maxBytes, buffer.length ) ); } catch (IOException e) { count = -1; } } while (count != -1); } 这样count和len就保持一致了。但问题来了:事实上inputStream还没读完的,所以WebResponse.getText()只有前半段内容,会比浏览器里查看时内容要少。这个很容易理解。 到现在我还不明白为什么明明count不为-1但是fill()方法却不能读流了呢?呵呵,继续研究。
真正解决方法在这里。
[第二篇]:
httpunit中java.io.EOFException: Unexpected end of ZLIB 的解决方法
2007-12-01 14:28 bobrow小作,允许自由转帖,但请注明出处和作者。谢谢。 今天凌晨写了一篇暂时解决httpunit异常“java.io.EOFException: Unexpected end of ZLIB ”的方法,今天起床仔细查看了httpunit1.6的WebResponse代码,在其defineRawInputStream方法中看到了感觉多于的代码:
final protected void defineRawInputStream( InputStream inputStream ) throws IOException {
if (_inputStream != null || _responseText != null) { throw new IllegalStateException( "Must be called before response text is defined." ); } if (encodedUsingGZIP()) {
byte[] compressedData = readFromStream( inputStream, getContentLength() ); _inputStream = new GZIPInputStream( new ByteArrayInputStream( compressedData ) ); } else { _inputStream = inputStream; } } 红色标记的两行代码是其原有的代码。把一个InputStream转型为GZIPInputStream不需要这么复杂吧?
于是我把代码一修改成如下:
final protected void defineRawInputStream( InputStream inputStream ) throws IOException {
if (_inputStream != null || _responseText != null) { throw new IllegalStateException( "Must be called before response text is defined." ); } if (encodedUsingGZIP()) {
_inputStream = new GZIPInputStream(inputStream); } else { _inputStream = inputStream; } } 蓝色标记代码为我修改的。呵呵,问题解决了。
后记:
1、其实为什么原代码处理GZIP流时会出错,而采用GZIPInputStream自带转型方式没问题,我也不是很明白,因为没去看GZIPInputStream到底是怎么转型的。得出的经验就是标准库有的方法,自己没必要去再实现一遍。
2、昨晚搜索了Google和百度N多文章,将近两小时的搜索也没有这个问题的结果。别人碰到过这个问题,但就是没人给出明确的解决方法。郁闷,只好自己动手解决了。
自己刚开始用的出错的方法:
public static byte[] gzipToXmlBytes(byte[] zipedfilebytes) {
ByteArrayInputStream bis = new ByteArrayInputStream(zipedfilebytes); GZIPInputStream gis = null ; try { pos += "f" ; byte[] buf = new byte[BUFSIZE]; gis = new GZIPInputStream(bis); int len = 0; int realsize=0; while ( (len = gis.read(buf)) >= 0) { ......... ......... .........
后来按照上面的提示,问题搞定了。
在手机上测试j2me gzip的解压表现:
把 a.gz文件[2.11M] 解压到手机[n6120c]文件系统里面,大概需要23秒钟左右.
解压后的文件为a.dat文件[2.23M]。 把 b.gz文件[423k] 解压到手机[n6120c]文件系统里面,大概需要5秒钟左右. 解压后的文件为b.dat文件[469k]。 大概平均一秒钟 80~90k . 不知道其它仁兄的结果如何? 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xiaoli_feng/archive/2008/03/27/2223361.aspx |
|