2014年4月

今天在写java读取gzip文件时,发现一直有问题,于是写了一段测试程序不断debug和验证。
测试代码大致是这样的:

    FileInputStream in = new FileInputStream("/tmp/from_gz");
    BufferedInputStream  bis = new BufferedInputStream(new GZIPInputStream(in));
    bis.skip(12568);
    IOUtils.copy(bis, new FileOutputStream("/tmp/outfile"));

经过测试发现,在PC上执行这段代码,生成的/tmp/outfile和预期文件是一致的,md5也吻合。但是在android上,生成的/tmp/outfile却截然不同,难道是android的GZIPInputStream有bug???

自己也觉得不太可能。于是一步步debug和分析了很久,去掉了GZIPInputStream包装,直接skip然后发现生成的两个md5是一样的。看来,原因就在于GZIPInputStream和skip。

后来想到以前遇到过的,在C语言下,调用read()函数去读取一个socket/pipe时,尽管你“期望”读取1024字节,但是也许read函数只返回800字节。我查看了skip函数的javadoc,发现果然有返回值long,进而猜测在android下,这个skip没有按照预期去skip掉12568这个“大”的一个数值。输出skip的返回值,果然只skip了564字节。分析其原因,在PC下OK应该是由于x86的系统有很强的cpu和内存,所以gzip对这个stream完全不是瓶颈,而android的arm平台则不一样,需要一边decode一边生成BufferedInputStream可以read的数据,而这时skip的速度快的多,因此超过了decode的速度。

看来,写任何IO的代码,包括磁盘和网络,都得时刻考虑性能和IO瓶颈的问题。