Java.io:性能调优

Java.io:性能调优,java,file-io,io,nio,filereader,Java,File Io,Io,Nio,Filereader,我有一个约4MB的文件,该文件是一个ascii文件,仅包含普通键盘字符。我在java.io包中尝试了许多类,以字符串形式读取文件内容。逐个字符读取它们(使用FileReader和BufferedReader)需要 大约40秒,使用java.nio包(FileChannel和ByteBuffer)读取内容大约需要25秒。这是从我的知识更大一点 时间量。有人知道如何将这段时间的消耗减少到一定程度吗 大约10秒?甚至像使用C创建文件读取器和从java调用这样的解决方案也可以。我使用下面的代码片段在22

我有一个约4MB的文件,该文件是一个ascii文件,仅包含普通键盘字符。我在java.io包中尝试了许多类,以字符串形式读取文件内容。逐个字符读取它们(使用FileReader和BufferedReader)需要 大约40秒,使用java.nio包(FileChannel和ByteBuffer)读取内容大约需要25秒。这是从我的知识更大一点 时间量。有人知道如何将这段时间的消耗减少到一定程度吗 大约10秒?甚至像使用C创建文件读取器和从java调用这样的解决方案也可以。我使用下面的代码片段在22秒内读取了4MB的文件-

public static String getContents(File file) {
    try {
        if (!file.exists() && !file.isFile()) {
            return null;
        }
        FileInputStream in = new FileInputStream(file);
        FileChannel ch = in.getChannel();
        ByteBuffer buf = ByteBuffer.allocateDirect(512);            
        Charset cs = Charset.forName("ASCII");          
        StringBuilder sb = new StringBuilder();
        int rd;
        while ((rd = ch.read(buf)) != -1) {
            buf.rewind();
            CharBuffer chbuf = cs.decode(buf);
            for (int i = 0; i < chbuf.length(); i++) {
                sb.append(chbuf.get());
            }
            buf.clear();
        }
        String contents = sb.toString();
        System.out.println("File Contents:\n"+contents);
        return contents;
    } catch (Exception exception) {
        System.out.println("Error:\n" + exception.getMessage());
        return null;
    }
}
公共静态字符串getContents(文件){
试一试{
如果(!file.exists()&&!file.isFile()){
返回null;
}
FileInputStream in=新的FileInputStream(文件);
FileChannel ch=in.getChannel();
ByteBuffer buf=ByteBuffer.allocateDirect(512);
Charset cs=Charset.forName(“ASCII”);
StringBuilder sb=新的StringBuilder();
国际公路;
而((rd=ch.read(buf))!=-1){
buf.倒带();
CharBuffer chbuf=cs.decode(buf);
对于(int i=0;i
我无法想象您的硬件可能是什么,但对于一个4 MB的文件,它应该需要不到0.1秒的时间

一次读取所有文件的快速方法是将其读入一个字节[]

public static String readFileAsString(File file) {
    try {
        DataInputStream in = new DataInputStream(FileInputStream(file));
        byte[] bytes = new byte[(int) file.length()];
        in.readFully(bytes);
        in.close();
        return new String(bytes, 0); // ASCII text only.

    } catch (FileNotFoundException e) {
        return null;
    } catch (IOException e) {
        System.out.println("Error:\n" + e.getMessage());
        return null;
    }
}

public static void main(String... args) throws IOException {
    File tmp = File.createTempFile("deleteme", "txt");
    tmp.deleteOnExit();

    byte[] bytes = new byte[4 * 1024 * 1024];
    Arrays.fill(bytes, (byte) 'a');
    FileOutputStream fos = new FileOutputStream(tmp);
    fos.write(bytes);
    fos.close();

    long start = System.nanoTime();
    String s = readFileAsString(tmp);
    long time = System.nanoTime() - start;
    System.out.printf("Took %.3f seconds to read a file with %,d bytes%n",
            time / 1e9, s.length());
}
印刷品

Took 0.026 seconds to read a file with 4,194,304 bytes

如果您想更快地读取该文件,我建议使用内存映射文件,因为它将花费不到10毫秒的时间,但在这种情况下,这是一种过度的杀伤力。

您可以增加缓冲区大小,比如说2048或4096字节

不要使用本机API,因为您不会获得编译时类型检查之类的Java特性

  • 在这里使用直接字节缓冲区没有任何好处
  • 您的512缓冲区太小。至少使用4096
  • 在这里使用NIO没有真正的好处。由于这是文本,我将使用BufferedReader
  • 将整个文件读入内存的基本目标是有缺陷的。它不会扩展,并且已经使用了过多的内存。您应该设计一种策略,一次一行地处理文件

  • 你为什么一个字节一个字节地读?您知道文件的大小-分配一个足够大的字节数组来保存文件内容,并使用read()完全读取。是的,您是对的,读取5 MB的文件(088毫秒)所需的时间非常少。但在控制台(System.out)上显示需要很长时间(40秒)。原因是什么?有人能解释一下吗?我原以为这40秒是用来阅读的,但实际上控制台更新屏幕的速度很慢。如果您使用的是MS-DOS控制台,那么它会非常慢。如果您想知道为什么MS-DOS控制台会慢,那是因为它自创建以来没有太大变化。系统输出速度非常慢。它正在假脱机到操作系统控制台。长时间explanation@mcfinnigan当重定向到文件时,System.out不慢。尝试
    javamyclass>output.txt
    ,您会发现它的速度非常快。