Java 快速读取文件的方法

Java 快速读取文件的方法,java,performance,file-io,Java,Performance,File Io,我正在开发一个有大约400个输入文件和大约40个输出文件的程序。 它很简单:它读取每个输入文件,然后生成一个新的文件,但要大得多(基于算法) 我正在使用BufferedReader中的read()方法: String encoding ="ISO-8859-1"; FileInputStream fis = new FileInputStream(nextFile); BufferedReader reader = new BufferedReader(new InputStreamReader

我正在开发一个有大约400个输入文件和大约40个输出文件的程序。 它很简单:它读取每个输入文件,然后生成一个新的文件,但要大得多(基于算法)

我正在使用BufferedReader中的read()方法:

String encoding ="ISO-8859-1";
FileInputStream fis = new FileInputStream(nextFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis, encoding));
char[] buffer = new char[8192] ;
要读取输入文件,我使用以下方法:

private String getNextBlock() throws IOException{
    boolean isNewFile = false;

    int n = reader.read(buffer, 0, buffer.length);
    if(n == -1) {
        return null;
    } else {
        return new String(buffer,0,n);
    }
}
对于每个块,我都要进行一些检查(比如在块中查找字符串),然后将其写入文件:

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
        new FileOutputStream("fileName"), encoding));

writer.write(textToWrite);
问题是大约需要12分钟。 我在试着更快地找到别的东西。 有人有更好的想法吗


谢谢。

您应该可以在这里找到答案:

要获得最佳Java读取性能,需要记住四件事:

  • 通过一次读取一个数组而不是一个字节来最小化I/O操作。8Kbyte数组大小合适

  • 通过一次获取一个数组而不是一个字节的数据来最小化方法调用。使用数组索引获取数组中的字节数

  • 如果不需要线程安全,请最小化线程同步锁。对线程安全类进行较少的方法调用,或者使用非线程安全类,如FileChannel和MappedByteBuffer

  • 尽量减少JVM/OS、内部缓冲区和应用程序阵列之间的数据复制。使用带有内存映射的FileChannel,或直接或包装的数组ByteBuffer


    • 由于您没有给出太多细节,我建议您尝试使用内存映射文件:

      FileInputStream f = new FileInputStream(fileName);
      FileChannel ch = f.getChannel( );
      MappedByteBuffer mbb = ch.map( ch.MapMode.READ_ONLY, 0L, ch.size( ) );
      while ( mbb.hasRemaining( ) )  {
            // Access the data using the mbb
      }
      
      如果你能提供更多关于你的文件中有哪种数据的细节,你就可以对它进行优化

      编辑

      其中是//使用mbb访问日期,您可以对文本进行冷解码:

      String charsetName = "UTF-16"; // choose the apropriate charset.
      CharBuffer cb =  Charsert.forName(charsetName).decode(mbb);
      String text = cb.toString();
      

      映射字节缓冲区是最快的方式:

       FileInputStream f = new FileInputStream( name );
      FileChannel ch = f.getChannel( );
      MappedByteBuffer mb = ch.map( ch.MapMode.READ_ONLY,
          0L, ch.size( ) );
      byte[] barray = new byte[SIZE];
      long checkSum = 0L;
      int nGet;
      while( mb.hasRemaining( ) )
      {
          nGet = Math.min( mb.remaining( ), SIZE );
          mb.get( barray, 0, nGet );
          for ( int i=0; i<nGet; i++ )
          checkSum += barray[i];
      }
      
      FileInputStream f=新的FileInputStream(名称);
      FileChannel ch=f.getChannel();
      MappedByteBuffer mb=ch.map(仅ch.MapMode.READ_,
      0升,总尺寸();
      byte[]baray=新字节[大小];
      长校验和=0L;
      int nGet;
      while(mb.haslaining())
      {
      nGet=Math.min(剩余mb(),大小);
      mb.get(barray,0,nGet);
      
      对于(int i=0;i您是否尝试过对不同的缓冲区大小进行基准测试?是文件IO中的瓶颈还是用于组合数据的算法中的瓶颈?@CC如果我的回答没有给您任何速度提升,您可以尝试将读取操作线程化。同时执行读取可以提高性能(但也可能降低性能)文件的大小是多少?硬盘的速度是多少?如果您正在读/写本地驱动器(网络驱动器会慢得多),则需要12分钟(例如6个驱动器正在读)文件的读写大小必须为10GB左右,或者平均读写大小为25MB,写写大小为250MB左右。这听起来对吗?如果是你的磁盘限制,那么I/O就不是你的瓶颈。仅链接的答案并不理想。你能至少总结一下这篇文章的发现吗?(谢谢!)OP希望将文件读取为文本。您可能希望在OP读取映射文件(如字节)时,包括如何使用默认编码(或UTF-8等特定编码)读取MappedByteBuffer,而不考虑赋位。在生成字符串时,OP需要指定编码:String s=新字符串(mbb.array(),Charset.UTF-8),注意数组是否已加载,如果未加载,则必须使用asCharBuffer()读取,还必须知道数组的大小和内容。啊,但关键在于细节。;(例如,如果字符串中的一个字节已读取,但另一个字节未读取,则无法解码该字符串。;)我不相信您可以调用
      mbb.array()
      在一张关于mbb.array的地图上,我错过了这个重要的细节。他将需要使用Charset.decode方法,我将使用它更新我的答案。+1:正确答案并不简单,因此添加一个示例非常有用。不适用于比Integer.MAX\u值大的大文件