在Java中读取相对较大的字节文件的最快方法

17

使用Java的I/O方法,最快的读取相对较大文件的方法是什么? 我目前的解决方案使用BufferedInputStream将数据保存到一个分配了1024个字节的字节数组中。 然后把每个缓冲区保存在ArrayList中以备后用。 整个过程通过一个单独的线程(callable接口)调用。

不过速度不太快。

    ArrayList<byte[]> outputArr = new ArrayList<byte[]>();      
    try {
        BufferedInputStream reader = new BufferedInputStream(new FileInputStream (dir+filename));

        byte[] buffer = new byte[LIMIT]; // == 1024 
            int i = 0;
            while (reader.available() != 0) {
                reader.read(buffer);
                i++;
                if (i <= LIMIT){
                    outputArr.add(buffer);
                    i = 0;
                    buffer = null;
                    buffer = new byte[LIMIT];
                }
                else continue;              
            }

         System.out.println("FileReader-Elements: "+outputArr.size()+" w. "+buffer.length+" byte each.");   

请查看Apache Commons库以获取更多选项。要确定速度,请查看O'Reilly的《Java性能调优》一书。 - therobyouknow
6
目前您正在忽略read()调用返回的值。请勿这样做 - Jon Skeet
3个回答

49

我会使用内存映射文件,在同一线程中执行速度足够快。

final FileChannel channel = new FileInputStream(fileName).getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());

// when finished
channel.close();

这假设文件大小小于2 GB,并且需要不到10毫秒的时间。


1
该死!为什么那个东西这么快?不管怎样,谢谢,完美地运行了。(编辑:它从内存中获取文件,Java文档告诉了我。聪明) - chollinger
2
如果您需要访问超过2GB的数据,则需要使用多个映射。 - Peter Lawrey
@PeterLawrey 同样的问题,有没有一种有效的方法将大型输入流转换为字节数组?例如,从 ContainerRequestContext 读取输入流? - Arnav Sengupta

4
不要使用available():它不可靠。并且不要忽略read()方法的结果:它告诉你实际读取了多少字节。如果想要在内存中读取所有内容,请使用ByteArrayOutputStream而不是使用List<byte[]>
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int read;
while ((read = reader.read(buffer)) >= 0) {
    baos.write(buffer, 0, read);
}
byte[] everything = baos.toByteArray();

我认为1024字节的缓冲区有点小,我会使用更大的缓冲区(例如16 KB或32 KB)。

请注意,Apache Commons IO和Guava都有实用方法可以为您完成此操作,并且已经进行了优化。


1

来看看Java NIO(非阻塞输入/输出)API。此外,这个问题可能会很有用。

我对IO没有太多经验,但我听说NIO是处理大量数据的更高效方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接