前言
最近项目上用到了压缩算法,找来找去找到了zip压缩算法,因为网上找的代码有点不太入法眼,所以找chatgpt写了个比较优雅的zip压缩解压算法,代码看起来还是比较漂亮的,殊不知其中隐藏了一个大bug!
起因
因为这个数据是准备压缩后,用扫码器到别的机器上识别的,一开始用的是加密算法,发现加密后字符串特别长,扫码器有点比较垃圾,所以只能在算法上想办法,思来想去,就找到了zip这个直接压缩字符串,一开始用的都比较顺畅,没什么问题!后来偶然的测试中发现,连续扫码解析的时候发现了问题,因为是在android系统上的,扫了几次应用直接退出了,但是日志里又么有发现异常的打印,就特别纳闷,第一次出现的时候,找日志没什么发现,就忽略了,但是后来又发现了,所以这个肯定是有什么问题!
一开始以为可能是扫码器连续读写的问题,但是想想,扫码器就是个键盘输入的东西,应该不会造成应用异常退出,但是后来想着不太对,估计还是哪里造成的,仔细看了下日志,发现最后一次读上来的码并不完整,难道是这个原因造成的,但是有try catch呀,应该不会造成的,抱着试试的态度,用java试了下,发现方法被阻塞了,一直没返回解密后的字符,有问题的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static String decompress(String compressedData) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Inflater inflater = new Inflater(); inflater.setInput(Base64.decode(compressedData));
byte[] buffer = new byte[1024]; while (!inflater.finished()) { int count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); }
inflater.end(); outputStream.close(); return outputStream.toString(); } catch (Exception e) { LogUtils.e("解压缩异常:", e); } return null; }
|
打断点后发现确实死循环了,inflater.finished()
这个方法一直都是false,所以无法退出,但是count一直是0,解铃还须系铃人,找chatgpt问了一下,回答如下:
Inflater
类的inflate
方法在解压缩数据时,如果提供的输入不足以产生完整的解压缩数据块,它可能会导致死循环。
为了解决这个问题,你可以在while
循环之前添加一个检查,确保至少提供了一些压缩数据。你可以使用inflater.needsInput()
方法来检查是否还需要更多的输入数据。完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static String decompress(String compressedData) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Inflater inflater = new Inflater();
byte[] compressedBytes = Base64.getDecoder().decode(compressedData); inflater.setInput(compressedBytes);
byte[] buffer = new byte[1024]; while (!inflater.finished() && !inflater.needsInput()) { int count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); }
inflater.end(); outputStream.close(); return outputStream.toString("UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; }
|
确实,你提到的是一个潜在的问题。Inflater
类的inflate
方法在解压缩数据时,如果提供的输入不足以产生完整的解压缩数据块,它可能会导致死循环。
为了解决这个问题,你可以在while
循环之前添加一个检查,确保至少提供了一些压缩数据。你可以使用inflater.needsInput()
方法来检查是否还需要更多的输入数据。
以下是修改后的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| javaCopy codeimport java.io.ByteArrayOutputStream; import java.util.Base64; import java.util.zip.Inflater;
public class YourClass { public static String decompress(String compressedData) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Inflater inflater = new Inflater();
byte[] compressedBytes = Base64.getDecoder().decode(compressedData); inflater.setInput(compressedBytes);
byte[] buffer = new byte[1024]; while (!inflater.finished() && !inflater.needsInput()) { int count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); }
inflater.end(); outputStream.close(); return outputStream.toString("UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; } }
|
这里添加了 !inflater.needsInput()
的条件,确保只有在Inflater
需要更多输入时才执行while
循环。这样可以避免死循环问题。
结语
所以chatgpt确实对写代码有帮助,但是有时候写出来的代码会有隐藏的问题,尤其是自己不太熟悉的方面,所以有时候不能太依赖,还是需要自己亲自验证试试!