【问题标题】:What is the quickest / most efficient way to append a char to a file loaded into memory?将字符附加到加载到内存中的文件的最快/最有效的方法是什么?
【发布时间】:2012-04-22 14:12:48
【问题描述】:
    read_data = new BufferedReader( new FileReader(args[0]) );
    data_buffer = new StringBuffer();

    int i;

    while(read_data.ready())
    {           
        while((i = read_data.read()) != -1)
        {
            data_buffer.append((char)i);
        }           
    }

    data_buffer.append(System.getProperty("line.separator"));

我想要做的是,将整个 .txt 文件读入一个字符串并在字符串中附加一个换行符。然后可以通过传递 data_buffer.toString() 创建一个新的 Scanner 来处理这个字符串。显然,对于非常大的文件,此过程会占用大量时间,而我要做的只是将换行符添加到已读入内存的 .txt 文件中。

我知道整个想法似乎有点古怪或奇怪,但有没有更快的方法?

干杯:)

【问题讨论】:

  • 好吧,至少,将 StringBuffer 初始化为文件的长度(如果你知道的话)或至少一个相当大的数字,以最小化重新分配操作。
  • 谢谢。我发现这个链接也做得很好,所以对于碰巧想知道我的人的其他人:weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner.html

标签: java file-io java.util.scanner


【解决方案1】:

做某事最快的方法往往是根本不做。

您为什么不修改解析代码,使末尾的换行符不需要?如果您每次都添加它,您也可以更改代码以使其表现得好像它确实存在而实际上不存在。

接下来我会尝试避免逐个字符地创建一个巨大的字符串,因为这确实是相当昂贵的。您可以基于InputStream 创建Scanner,它可能比将数据读入String 并解析它要快得多。您可以覆盖 FileInputStream 以在文件末尾返回一个虚拟换行符,从而避免粘贴字符串的实例化。

如果您确实必须将数据读入缓冲区,则最好使用基于数组的read() 流方法读入字节数组 - 比逐字节快得多。由于您可以提前知道文件的大小,因此您可以为缓冲区分配空间以放置额外的行尾标记并将其插入数组中。与创建StringBuffer 并从中创建String 相比,这不需要缓冲区的完整副本。

【讨论】:

    【解决方案2】:

    据我所知,您实际上试图做的是以这样一种方式读取文件,即在最后一行的末尾似乎总是有一个行分隔符。

    如果是这种情况,那么您可以通过实现FilterReader 的子类型来做到这一点,并在到达字符流末尾时让它“插入”一个或两个额外的字符。

    执行此操作的代码并不简单,但可以避免在内存中缓冲整个文件的时间和空间开销。

    【讨论】:

      【解决方案3】:

      如果您所做的只是将生成的文件传递给 Scanner,您应该为该文件创建一个 Readable 并将其发送给 Scanner。

      这是一个例子(未经测试):

      public class NLReader implements Readable {
      
          Reader r;
          boolean atEndOfReader = false;
          boolean atEnd = false;
      
          public NLReader(Reader r) {
              this.r = r;
          }
      
          public int read(CharBuffer cb) throws IOException {
              if (!atEndOfReader) {
                  int result = r.read(cb);
                  if (result == -1) {
                      atEndOfReader = true;
                  } else {
                      return result;
                  }
              }
              if (!atEnd) {
                  String nl = System.getProperty("line.separator");
                  cb.append(nl);
                  atEnd = true;
                  return nl.length();
              }
      
              return -1;
          }
      }
      

      这只会读取文件一次,从不复制它(与您的 StringBuffer 不同——除非您真的需要 StringBuffer 的同步,否则您应该使用 StringBuilder)。

      这也不会将实际文件加载到内存中,因此也可以节省内存压力。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-16
        • 1970-01-01
        • 2012-12-09
        • 2015-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-30
        相关资源
        最近更新 更多