我目前正在尝试找到在java中搜索2GB二进制文件的最快方法。这与我的正常问题不同,因为此文件已使用mmap
内存映射到Linux文件系统。
文件是一个二进制文件,我需要搜索一个固定的四字节字符串; AXL0
通常,在较小的文件上,我只是缓冲它,将其转换为字符串,然后正则表达它。但是,由于这个文件已经是内存映射的,并且非常大,重新缓冲它的想法似乎是错误的,并且将其转换为2GB字符串似乎更加冤枉...
经过一些阅读后,我发现了Java NIO
包以及FileChannels
和MappedByteBuffers
,但我不完全确定如何设置它们。
我只需要扫描文件,从零到文件中的最后一个字节,并找到四个字节字符串的每个实例。
如果有人可以提供一些建议或意见,我会非常感激。
感谢。
答案 0 :(得分:3)
抽象地看待这个任务,你不能做任何比线性搜索更好的事情。
从下面开始,使用哪种API来实际执行搜索并不重要,为简单起见,我只想使用缓冲的InputStream,它可以实现与实际数据源无关,并且没有固有的限制阻止它来自大于2GB的文件。
只要您选择合理的缓冲区大小(读取:不太小),您应该获得合理的性能(因为接近实际的I / O速度限制,除了可能是因为您的扫描可能需要比那种情况下的实际I / O.)
编辑:在KISS之后,你会得到几行应该做得很好的代码
public class ScanForByteCombo {
public static List<Long> scanFor(InputStream is, int needle) throws IOException {
List<Long> foundOffsets = new ArrayList<>();
InputStream bs = new BufferedInputStream(is, 0x10000);
int data = 0;
int b;
long offset = 0;
while ((b = bs.read()) != -1) {
data = (data << 8) | b;
if (data == needle)
foundOffsets.add(offset);
++offset;
}
return foundOffsets;
}
public static void main(String[] argv) {
int needle = ('A' << 24) | ('X' << 16) | ('F' << 8) | '0';
long start = System.currentTimeMillis();
try (InputStream is = new FileInputStream("your file")) {
List<Long> found = scanFor(is, needle);
System.out.println(found);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("scan took " + (System.currentTimeMillis() - start) + "ms. Acceptable?");
}
}
虽然它看起来效率很低,但你可能不得不竭尽全力以值得注意的金额来提高性能。