从临时目录读取 SQLite 文件时获取 java.io.EOFException
Getting java.io.EOFException while reading a SQLite file from temp directory
我在从临时目录读取 SQLite
文件时看到 EOFException 异常。以下是读取文件的代码。而且并不总是看到异常。考虑在 50K 个文件中出现 3 到 4 次。
public static byte[] decompressLzmaStream(InputStream inputStream, int size)
throws CompressorException, IOException {
if(size < 1) {
size = 1024 * 100;
}
try(LZMACompressorInputStream lzmaInputStream =
new LZMACompressorInputStream(inputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(size)) {
byte[] buffer = new byte[size];
int length;
while (-1 != (length = lzmaInputStream.read(buffer))) {
byteArrayOutputStream.write(buffer, 0, length);
}
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
}
我正在使用以下依赖项进行解压
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
</dependency>
在 while (-1 != (length = lzmaInputStream.read(buffer))) {
行抛出异常。以下是例外。
java.io.EOFException: null at java.io.DataInputStream.readUnsignedByte(DataInputStream.java:290)
at org.tukaani.xz.rangecoder.RangeDecoderFromStream.normalize(Unknown Source)
at org.tukaani.xz.rangecoder.RangeDecoder.decodeBit(Unknown Source)
at org.tukaani.xz.lzma.LZMADecoder.decode(Unknown Source)
at org.tukaani.xz.LZMAInputStream.read(Unknown Source)
at org.apache.commons.compress.compressors.lzma.
LZMACompressorInputStream.read(LZMACompressorInputStream.java:62)
at java.io.InputStream.read(InputStream.java:101)
任何人都知道 commons-compress
.
的以下构造函数
// I am using this constructor of LZMACompressorInputStream
public LZMACompressorInputStream(InputStream inputStream) throws IOException {
this.in = new LZMAInputStream(this.countingStream = new CountingInputStream(inputStream), -1);
}
// This is added in later version of commons-compress, what is memoryLimitInKb
public LZMACompressorInputStream(InputStream inputStream, int memoryLimitInKb) throws IOException {
try {
this.in = new LZMAInputStream(this.countingStream = new CountingInputStream(inputStream), memoryLimitInKb);
} catch (MemoryLimitException var4) {
throw new org.apache.commons.compress.MemoryLimitException((long)var4.getMemoryNeeded(), var4.getMemoryLimit(), var4);
}
}
正如我所读对于 LZMA 流,我们需要将未压缩的大小传递给此处的构造函数 --> https://issues.apache.org/jira/browse/COMPRESS-286?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel&focusedCommentId=14109417#comment-14109417
LZMA 解码器需要知道压缩流何时结束。如果在压缩期间已知未压缩的大小,则流的 header (位于流的开头)
将包含未压缩的大小。当解码器的输出达到这个大小时,解码器就知道
到达流的末尾。如果在压缩期间不知道未压缩的大小,则 header 将
不包含尺寸。在这种情况下,编码器假定流明确地终止于
流标记结束。
由于 LZMA 流也用于 7z 和 xz 等容器格式,LZMAOutputStream
并且 LZMAInputStream
classes 还为 reading/writing 流提供构造器,而没有 header.
COMPRESS-286 是关于解压缩一个 7z 档案,其中包含一个使用 LZMA 压缩的条目。 7z 存档包含没有 header 的 LZMA 流。通常存储在 LZMA 的 header 中的信息与流分开存储。
用于读取 7z 档案的 Apache commons SevenZFile
class 使用以下构造函数创建 LZMAInputStream
objects:
LZMAInputStream(InputStream in, long uncompSize, byte propsByte, int dictSize)
构造函数的附加参数表示通常存储在LZMA流开头的header中的信息。 COMPRESS-286 的修复确保未压缩的大小(之前丢失)也被移交给 LZMAInputStream。
LZMACompressorInputStream
也使用 LZMAInputStream
但它假设压缩流包含显式 header。因此不可能通过它的构造函数传递信息。
memoryLimitInKb
参数只限制解压使用的内存,与解压后的大小无关。所需内存的主要贡献者是所选字典的大小。此大小在压缩期间指定,并且也存储在流的 header 中。其最大值为 4 GB。通常字典的大小小于未压缩的大小。大于未压缩大小的字典绝对是内存浪费。损坏的 LZMA header 很容易导致 OOM 错误,并且被操纵的流甚至为拒绝服务攻击打开了大门。因此,当您读取未经验证的 LZMA 流时,限制最大内存使用量是明智的。
总结:由于您没有阅读带有 LZMA 压缩条目的 7z 存档,COMPRESS-286 与您的问题无关。但是类似的堆栈跟踪可能表明您的流的 header 有问题。
确保使用 LZACompressorOutputStream
的实例压缩数据(自动选择
字典大小,所有其他参数并确保写入 header)。如果您应该直接使用 LZAOutputStream
,请确保您使用的实例实际写入 header.
我在从临时目录读取 SQLite
文件时看到 EOFException 异常。以下是读取文件的代码。而且并不总是看到异常。考虑在 50K 个文件中出现 3 到 4 次。
public static byte[] decompressLzmaStream(InputStream inputStream, int size)
throws CompressorException, IOException {
if(size < 1) {
size = 1024 * 100;
}
try(LZMACompressorInputStream lzmaInputStream =
new LZMACompressorInputStream(inputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(size)) {
byte[] buffer = new byte[size];
int length;
while (-1 != (length = lzmaInputStream.read(buffer))) {
byteArrayOutputStream.write(buffer, 0, length);
}
byteArrayOutputStream.flush();
return byteArrayOutputStream.toByteArray();
}
}
我正在使用以下依赖项进行解压
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.20</version>
</dependency>
在 while (-1 != (length = lzmaInputStream.read(buffer))) {
行抛出异常。以下是例外。
java.io.EOFException: null at java.io.DataInputStream.readUnsignedByte(DataInputStream.java:290)
at org.tukaani.xz.rangecoder.RangeDecoderFromStream.normalize(Unknown Source)
at org.tukaani.xz.rangecoder.RangeDecoder.decodeBit(Unknown Source)
at org.tukaani.xz.lzma.LZMADecoder.decode(Unknown Source)
at org.tukaani.xz.LZMAInputStream.read(Unknown Source)
at org.apache.commons.compress.compressors.lzma.
LZMACompressorInputStream.read(LZMACompressorInputStream.java:62)
at java.io.InputStream.read(InputStream.java:101)
任何人都知道 commons-compress
.
// I am using this constructor of LZMACompressorInputStream
public LZMACompressorInputStream(InputStream inputStream) throws IOException {
this.in = new LZMAInputStream(this.countingStream = new CountingInputStream(inputStream), -1);
}
// This is added in later version of commons-compress, what is memoryLimitInKb
public LZMACompressorInputStream(InputStream inputStream, int memoryLimitInKb) throws IOException {
try {
this.in = new LZMAInputStream(this.countingStream = new CountingInputStream(inputStream), memoryLimitInKb);
} catch (MemoryLimitException var4) {
throw new org.apache.commons.compress.MemoryLimitException((long)var4.getMemoryNeeded(), var4.getMemoryLimit(), var4);
}
}
正如我所读对于 LZMA 流,我们需要将未压缩的大小传递给此处的构造函数 --> https://issues.apache.org/jira/browse/COMPRESS-286?page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel&focusedCommentId=14109417#comment-14109417
LZMA 解码器需要知道压缩流何时结束。如果在压缩期间已知未压缩的大小,则流的 header (位于流的开头) 将包含未压缩的大小。当解码器的输出达到这个大小时,解码器就知道 到达流的末尾。如果在压缩期间不知道未压缩的大小,则 header 将 不包含尺寸。在这种情况下,编码器假定流明确地终止于 流标记结束。
由于 LZMA 流也用于 7z 和 xz 等容器格式,LZMAOutputStream
并且 LZMAInputStream
classes 还为 reading/writing 流提供构造器,而没有 header.
COMPRESS-286 是关于解压缩一个 7z 档案,其中包含一个使用 LZMA 压缩的条目。 7z 存档包含没有 header 的 LZMA 流。通常存储在 LZMA 的 header 中的信息与流分开存储。
用于读取 7z 档案的 Apache commons SevenZFile
class 使用以下构造函数创建 LZMAInputStream
objects:
LZMAInputStream(InputStream in, long uncompSize, byte propsByte, int dictSize)
构造函数的附加参数表示通常存储在LZMA流开头的header中的信息。 COMPRESS-286 的修复确保未压缩的大小(之前丢失)也被移交给 LZMAInputStream。
LZMACompressorInputStream
也使用 LZMAInputStream
但它假设压缩流包含显式 header。因此不可能通过它的构造函数传递信息。
memoryLimitInKb
参数只限制解压使用的内存,与解压后的大小无关。所需内存的主要贡献者是所选字典的大小。此大小在压缩期间指定,并且也存储在流的 header 中。其最大值为 4 GB。通常字典的大小小于未压缩的大小。大于未压缩大小的字典绝对是内存浪费。损坏的 LZMA header 很容易导致 OOM 错误,并且被操纵的流甚至为拒绝服务攻击打开了大门。因此,当您读取未经验证的 LZMA 流时,限制最大内存使用量是明智的。
总结:由于您没有阅读带有 LZMA 压缩条目的 7z 存档,COMPRESS-286 与您的问题无关。但是类似的堆栈跟踪可能表明您的流的 header 有问题。
确保使用 LZACompressorOutputStream
的实例压缩数据(自动选择
字典大小,所有其他参数并确保写入 header)。如果您应该直接使用 LZAOutputStream
,请确保您使用的实例实际写入 header.