Java:InputStream太慢,无法读取大型文件

Java:InputStream太慢,无法读取大型文件,java,inputstream,large-files,java-native-interface,Java,Inputstream,Large Files,Java Native Interface,我必须逐字读取一个53MB的文件。当我在C++中使用IFFILE时,它是以毫秒为单位完成的,但是使用java输入流需要几分钟。Java这么慢是正常的还是我遗漏了什么 另外,我需要用Java完成这个程序(它使用servlet,我必须从中调用处理这些字符的函数)。我在想也许用C或C++编写文件处理部分,然后用java本地接口来与java程序接口这些函数…这个主意怎么样 有谁能给我其他的建议吗。。。我真的需要更快地阅读文件。我尝试使用缓冲输入,但它仍然不提供性能甚至接近C++。p> 编辑:我的代码跨越

我必须逐字读取一个53MB的文件。当我在C++中使用IFFILE时,它是以毫秒为单位完成的,但是使用java输入流需要几分钟。Java这么慢是正常的还是我遗漏了什么

另外,我需要用Java完成这个程序(它使用servlet,我必须从中调用处理这些字符的函数)。我在想也许用C或C++编写文件处理部分,然后用java本地接口来与java程序接口这些函数…这个主意怎么样

有谁能给我其他的建议吗。。。我真的需要更快地阅读文件。我尝试使用缓冲输入,但它仍然不提供性能甚至接近C++。p> 编辑:我的代码跨越多个文件,而且非常脏,所以我给出了概要

import java.io.*;

public class tmp {
    public static void main(String args[]) {
        try{
        InputStream file = new BufferedInputStream(new FileInputStream("1.2.fasta"));
        char ch;        
        while(file.available()!=0) {
            ch = (char)file.read();
                    /* Do processing */
            }
        System.out.println("DONE");
        file.close();
        }catch(Exception e){}
    }
}
使用:


如上所述,使用BufferedInputStream。您还可以使用NIO包。请注意,对于大多数文件,BufferedInputStream的读取速度与NIO一样快。但是,对于非常大的文件,NIO可能会做得更好,因为您可以使用内存映射文件操作。此外,NIO包不支持可中断IO,而java.IO包不支持。这意味着,如果要从另一个线程取消操作,必须使用NIO使其可靠

ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
FileChannel fileChannel = fileInputStream.getChannel();
int readCount = 0;
while ( (readCount = fileChannel.read(buf)) > 0) {
  buf.flip();
  while (buf.hasRemaining()) {
    byte b = buf.get();
  }
  buf.clear();
}

我用183MB的文件运行了这段代码。它打印了“经过250毫秒”

我想试试这个

// create the file so we have something to read.
final String fileName = "1.2.fasta";
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(new byte[54 * 1024 * 1024]);
fos.close();

// read the file in one hit.
long start = System.nanoTime();
FileChannel fc = new FileInputStream(fileName).getChannel();
ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
while (bb.remaining() > 0)
    bb.getLong();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to read %.1f MB%n", time / 1e9, fc.size() / 1e6);
fc.close();
((DirectBuffer) bb).cleaner().clean();
印刷品

Took 0.016 seconds to read 56.6 MB


给我们看看你的代码。如果不了解您的工作方式,我们无法猜测您的问题。您是否正在使用
BufferedInputStream
?你应该在BufferedReader上使用它。您的访问模式是否允许您使用
java.nio
对文件的某些部分进行内存映射?具体地说,当你说“
char
by
char
”时,你是否对编码有足够的了解,以处理字节序列可能分布在多个内存映射段的
char
字符?光是读取这些53M字符而不做任何其他事情可能需要几秒钟以上,缓冲或无缓冲。肯定还有其他问题。逐个字符读取可能是您的问题。您使用的
file.available()
不正确。试试这个,
while((ch=(char)file.read())>=0)
并删除
ch=(char)file.read()我也使用了BufferedInputStream。InputStream fh=新的BufferedInputStream(新文件InputStream(“文件”));我不认为内存映射文件对顺序读取有任何好处。@MarkoTopolnik它们对任何事情的时间好处都不超过20%,但我不知道为什么您认为顺序读取是一种特殊情况。事实并非如此。磁盘仍然进行预读,就像您使用流或读卡器时一样。@EJP是的,但预读无论如何都是在较低的级别上进行的(即使在磁盘电子设备中,也在磁盘缓存实现中).@MarkoTopolnik为什么MM文件不适合顺序读取?@EJP MM文件主要是为了方便随机访问读取,因为它们提供了一个简单的API来访问文件,就像它是RAM中的数组一样。如果您所做的只是自上而下地运行一个MM文件,那么您只会给内存管理器带来压力,而不会从paradigm.Nice中获得任何好处。另外,我需要逐个字符地处理文件。因此,我不会从文件中读取单个字符,而是从缓冲区中检索它,如果它用完了,则再次填充它。非常感谢:是的,我认为java会陷入方法调度,C++可能会嵌入调用。有时在足够多的调用之后,HotSpot也会将调用内联,但我不能确定这种情况。@MarkoTopolnik这里没有证据表明Java在任何事情上都“陷入困境”,除了调用InputStream.available()5300万次,这是5300万次冗余系统调用。由于他使用的是BufferedInputStream,实际读取文件的系统调用数为53/81.92亿次,因此调用available()是一项巨大的开销。@MarkoTopolnik我使用
BufferedInputStream.read(byte[])
获得676ms;2441ms和
FileInputStream.read(字节[])
,610ms通过
BufferedInputStream.read()
(一次一个字节)。具有随机内容的不同文件(以避免缓存),全部183MB,1000字节缓冲区。爪哇6。几次运行的结果都相当一致。没有出现50x问题的迹象。@EJP OK,所以我们可能讨论的是OS X上糟糕的实现。在我阅读了您的结果后,我再次检查了我的。它是真实的。未找到DirectBuffer符号。所以我删除了最后一行,但运行它时抛出了java.nio.BufferUnderflowException。(53.4 MB文件)我一次读取8个字节以提高速度,如果长度不是8的倍数,这是不好的。您可以改用
bb.get()
。DirectBuffer位于
sun.nio.ch
中,这使得它成为一个可以删除的内部使用API。
// create the file so we have something to read.
final String fileName = "1.2.fasta";
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(new byte[54 * 1024 * 1024]);
fos.close();

// read the file in one hit.
long start = System.nanoTime();
FileChannel fc = new FileInputStream(fileName).getChannel();
ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
while (bb.remaining() > 0)
    bb.getLong();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to read %.1f MB%n", time / 1e9, fc.size() / 1e6);
fc.close();
((DirectBuffer) bb).cleaner().clean();
Took 0.016 seconds to read 56.6 MB