问题复现
public class CompressionUtilsA {
public static byte[] compress(String str) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(str.getBytes());
}
return out.toByteArray();
}
public static String decompress(byte[] compressedData) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(compressedData))) {
byte[] buffer = new byte[1024];
int len;
while ((len = gzip.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
return out.toString();
}
}
如果字符串压缩方法compress方法中str字符串长度超过2G个字节,直接用str.getBytes()会报错,报错信息是使用负数下标去访问数组。
[2023-11-30 12:21:12] [8624-main] ......
error! java.lang.NegativeArraySizeException: -1713775714
at java.lang.String.encodeUTF8_UTF16(String.java:1298) ~[?:?]
at java.lang.String.encodeUTF8(String.java:1274) ~[?:?]
at java.lang.String.encode(String.java:847) ~[?:?]
at java.lang.String.getBytes(String.java:1811) ~[?:?]
at ...utils.CompressionUtils.compress(CompressionUtils.java:19) ~[classes/:?]
问题原因
如果这里的val数组非常大,超过了2G,这里使用了int去接收一个超过了1024 * 1024 * 1024即2G的数字,导致越界,变为了负数,所以会有上面的负下标数组的报错信息。
解决方案
方案1:在调用String.getBytes之前对原始字符串进行拆分,保证每个子串长度不超过2G。
方案2:调用jdk中String.getBytes的其他重载方法,支持按长度截取字节流