【问题标题】:in java how to efficiently read x lines from a file, close it, and then open it again, starting at line x and continue reading在java中如何有效地从文件中读取x行,关闭它,然后再次打开它,从第x行开始并继续阅读
【发布时间】:2011-05-04 14:49:12
【问题描述】:

BufferedReader 具有简单的方法来逐行读取文件。但是似乎没有任何方法可以跟踪您所在的位置,因此您可以稍后再回到那个地方。 FileInputStream 有文件 getChannel() ,它返回一个 FileChannel ,它可以告诉你流中的当前位置。因此,如果你给 BufferedReader 一个 FileInputStream 来读取,你可以在 FileInputStream 中找出 BufferedReader 停止读取的位置,并且你也可以在将 FileInputStream 给到缓冲阅读器之前将它设置到那个位置。

问题在于 BufferedReader 已提前读取文件。所以FileInputStream的位置和BufferedReader中的位置是不一样的。您可能从 BufferedReader 中读取了 20 行,但 BufferedReader 可能从 FileInputStream 中读取了 30 行。如果稍后您根据 FileInputStream 中的位置重新打开文件,您将错过中间的 10 行。

我可以从 InputStream 中逐个字符地阅读,但似乎有更好的方法...

【问题讨论】:

标签: java file-io


【解决方案1】:

这是一个使用现有 Java 类解决的极其困难的问题。出于一个原因,您忽略了一个事实,即您实际上不能将 InputStream 传递给 BufferedReader,您需要传递 Reader。

文件以字节为单位,而阅读器以字符为单位。由于任何给定字符都可以在任意字符集中占用任意数量的字节,因此您需要记录 每个字符 占用的字节数才能计算出特定数量的字节数文件中表示的字符数。

如果您愿意采用一种非常脆弱的方法,您可以假设文件中的每个字节都代表一个字符(例如 ASCII),并且每一行都以"\n" 结尾。那么这只是记录你读过多少个字符的问题。像这样的:

public class CountingBufferedReader extends BufferedReader {
     private int position = 0;
     public String readLine() {
        String line = super.readLine();
        position += line.length() + 1;
        return line;
     }

     public int getPosition() {
         return position;
     }
}

使其对任何输入和任何字符集都通用要困难得多,并且可能需要重写许多现有类以提高效率。

【讨论】:

  • 我不认为“您实际上不能将 InputStream 传递给 BufferedReader,您需要传递 Reader”这句话是正确的。以下代码完全有效。 InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr);
  • @Pangea:InputStreamReader IS-A Reader,而不是 InputStream。这是一个有用的适配器。与FileReader 一样,它直接获取文件,因此您甚至不需要直接处理 InputStream。关键是阅读器用字节处理字符和输入流,从一个到另一个不一定有一个常量映射。
【解决方案2】:

它可能无法完全回答您的问题,但 Apache IOUtils 会将 Stream 读入列表 http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#readLines%28java.io.InputStream%29

然后你可以直接访问列表中的任何一行(流将被关闭)

来自他们的文档:

public static List readLines(InputStream input)
                      throws IOException

    Get the contents of an InputStream as a list of Strings, one entry per line, using the default character encoding of the platform.

    This method buffers the input internally, so there is no need to use a BufferedInputStream.

    Parameters:
        input - the InputStream to read from, not null 
    Returns:
        the list of Strings, never null 
    Throws:
        NullPointerException - if the input is null 
        IOException - if an I/O error occurs
    Since:
        Commons IO 1.1

【讨论】:

  • 这只有在你可以将整个文件放入内存时才有效。能做就很好,不能做也没用。
【解决方案3】:

使用 java.io.LineNumberReader 类。这告诉你你目前在哪条线上。下一次就读那么多行。这确实使您的问题成为 O(N**X),其中 X 是您读取文件的次数,但是为什么您仍然只读取文件的一部分呢?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多