我正在使用Kaitai-Struct在Java中解析大型PCAP文件。每当文件大小超过Integer.MAX_VALUE
个字节时,我都会遇到由基础IllegalArgumentException
的大小限制引起的ByteBuffer
。
我没有在其他地方找到对此问题的引用,这使我相信这不是库限制,而是我使用它的方式上的错误。
由于问题是由于尝试将整个文件映射到ByteBuffer
引起的,因此我认为解决方案将仅映射文件的第一个区域,并且由于数据被消耗,因此再次跳过了映射已解析的数据。
由于这是在Kaitai Struct运行时库中完成的,这意味着要编写我自己的类来扩展fom KatiaiStream
并覆盖自动生成的fromFile(...)
方法,这似乎并不正确方法。
从文件中自动解析出PCAP类的方法是
。public static Pcap fromFile(String fileName) throws IOException {
return new Pcap(new ByteBufferKaitaiStream(fileName));
}
并且Kaitai Struct运行时库提供的ByteBufferKaitaiStream
由ByteBuffer
支持。
private final FileChannel fc;
private final ByteBuffer bb;
public ByteBufferKaitaiStream(String fileName) throws IOException {
fc = FileChannel.open(Paths.get(fileName), StandardOpenOption.READ);
bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
}
依次受ByteBuffer
的最大大小限制。
我缺少一些明显的解决方法吗?它真的是在Java中实施Katiati Struct的限制吗?
答案 0 :(得分:1)
此库提供了使用long
偏移量的ByteBuffer实现。我没有尝试过这种方法,但是看起来很有希望。请参见映射大于2 GB的文件
http://www.kdgregory.com/index.php?page=java.byteBuffer
public int getInt(long index)
{
return buffer(index).getInt();
}
private ByteBuffer buffer(long index)
{
ByteBuffer buf = _buffers[(int)(index / _segmentSize)];
buf.position((int)(index % _segmentSize));
return buf;
}
public MappedFileBuffer(File file, int segmentSize, boolean readWrite)
throws IOException
{
if (segmentSize > MAX_SEGMENT_SIZE)
throw new IllegalArgumentException(
"segment size too large (max " + MAX_SEGMENT_SIZE + "): " + segmentSize);
_segmentSize = segmentSize;
_fileSize = file.length();
RandomAccessFile mappedFile = null;
try
{
String mode = readWrite ? "rw" : "r";
MapMode mapMode = readWrite ? MapMode.READ_WRITE : MapMode.READ_ONLY;
mappedFile = new RandomAccessFile(file, mode);
FileChannel channel = mappedFile.getChannel();
_buffers = new MappedByteBuffer[(int)(_fileSize / segmentSize) + 1];
int bufIdx = 0;
for (long offset = 0 ; offset < _fileSize ; offset += segmentSize)
{
long remainingFileSize = _fileSize - offset;
long thisSegmentSize = Math.min(2L * segmentSize, remainingFileSize);
_buffers[bufIdx++] = channel.map(mapMode, offset, thisSegmentSize);
}
}
finally
{
// close quietly
if (mappedFile != null)
{
try
{
mappedFile.close();
}
catch (IOException ignored) { /* */ }
}
}
}
答案 1 :(得分:1)
这里有两个独立的问题:
对大型文件运行Pcap.fromFile()
通常不是一种非常有效的方法,因为您最终会一次性将 all 个文件解析到内存阵列中。 kaitai_struct/issues/255中提供了有关如何避免这种情况的示例。基本思想是,您希望控制如何读取每个数据包,然后以某种方式对其进行解析/计算后再处理每个数据包。
2GB。为了减轻这种情况,您可以使用替代的基于RandomAccessFile的KaitaiStream实现:RandomAccessFileKaitaiStream —可能会更慢,但应避免出现2GB的问题。