Java 中排序(内存映射?)文件中的二分搜索

2024-05-04

我正在努力将 Perl 程序移植到 Java,并一边学习 Java。原始程序的核心组成部分是Perl模块 http://search.cpan.org/~jfreeman/File-SortedSeek-0.015/lib/File/SortedSeek.pm使用二分搜索在 +500 GB 排序文本文件中进行字符串前缀查找 (本质上,“查找”到文件中间的字节偏移量,回溯到最近的换行符,将行前缀与搜索字符串进行比较,“查找”到该字节偏移量的一半/两倍,重复直到找到......)

我已经尝试了几种数据库解决方案,但发现对于这种大小的数据集,在纯粹的查找速度上没有什么比这更好的了。您知道现有的 Java 库可以实现此类功能吗?如果做不到这一点,你能给我指出一些随机访问读取文本文件的惯用示例代码吗?

或者,我不熟悉新的(?)Java I/O 库,但是可以选择内存映射 500 GB 文本文件(我在一台有空闲内存的 64 位机器上)并执行二进制操作搜索内存映射字节数组?我非常有兴趣听到您分享有关此问题和类似问题的任何经验。


I am a bigJava 的粉丝MappedByteBuffers http://download.oracle.com/javase/1.5.0/docs/api/index.html?java/nio/MappedByteBuffer.html对于这样的情况。它的速度非常快。下面是我为您整理的一个片段,它将缓冲区映射到文件,查找中间,然后向后搜索到换行符。这应该足以让你继续下去吧?

我在自己的应用程序中有类似的代码(查找、读取、重复直到完成),并进行了基准测试java.io流反对MappedByteBuffer在生产环境中并将结果发布在我的博客上(Geekomatic 帖子标记为“java.nio” http://geekomatic.ch/tags/java.nio/)包含原始数据、图表等。

两秒总结?My MappedByteBuffer基于 的实施速度大约提高了 275%。 YMMV.

要处理大于 ~2GB 的文件,这是一个问题,因为转换和.position(int pos),我精心设计了由一系列支持的分页算法MappedByteBuffers。您需要在 64 位系统上工作才能处理大于 2-4GB 的文件,因为 MBB 使用操作系统的虚拟内存系统来发挥其魔力。

public class StusMagicLargeFileReader  {
    private static final long PAGE_SIZE = Integer.MAX_VALUE;
    private List<MappedByteBuffer> buffers = new ArrayList<MappedByteBuffer>();
    private final byte raw[] = new byte[1];

    public static void main(String[] args) throws IOException {
        File file = new File("/Users/stu/test.txt");
        FileChannel fc = (new FileInputStream(file)).getChannel(); 
        StusMagicLargeFileReader buffer = new StusMagicLargeFileReader(fc);
        long position = file.length() / 2;
        String candidate = buffer.getString(position--);
        while (position >=0 && !candidate.equals('\n')) 
            candidate = buffer.getString(position--);
        //have newline position or start of file...do other stuff    
    }
    StusMagicLargeFileReader(FileChannel channel) throws IOException {
        long start = 0, length = 0;
        for (long index = 0; start + length < channel.size(); index++) {
            if ((channel.size() / PAGE_SIZE) == index)
                length = (channel.size() - index *  PAGE_SIZE) ;
            else
                length = PAGE_SIZE;
            start = index * PAGE_SIZE;
            buffers.add(index, channel.map(READ_ONLY, start, length));
        }    
    }
    public String getString(long bytePosition) {
        int page  = (int) (bytePosition / PAGE_SIZE);
        int index = (int) (bytePosition % PAGE_SIZE);
        raw[0] = buffers.get(page).get(index);
        return new String(raw);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 中排序(内存映射?)文件中的二分搜索 的相关文章

随机推荐