readLine() 从 1 行读取两次



我正在尝试读取文件的行。我第一次使用br.readLine()它读取第一行。第二次读取第二行等。但是,我喜欢第二次再次从第一行开始。我需要做什么才能告诉它重新开始?

br.readLine(); //reading first line
br.readLine(); //I want it to read first line again

假设"br"是一个缓冲阅读器,你可以尝试

assert br.markSupported();
br.mark(256); // assumes lines shorter than 256 characters
line1 = br.readLine();
br.reset();
line2 = br.readLine();

请参阅文档。

话虽如此,我不清楚为什么你需要把这一行读两遍。为什么你不能只读一次,用两次?

基本的结果是:这是不可能的

BufferedReader 基本上是一个流概念。

假设您有一个文件直接通过大小为 20GB 的网络进行流式传输。将到目前为止发送的所有数据的副本保留在内存中是不可行的,以防万一您可能希望在某个时候从头开始。将副本保存到磁盘也是不可行的。如果您不需要返回,这会减慢一切速度并浪费 20GB 的磁盘空间,而您通常不需要。

也许你会说:啊,但它已经是一个文件了。好的,但是BufferedReader是一个抽象,它同样适用于通过网络流式传输的数据。这种抽象不允许你 - 因为如果它这样做,它就不能用于像这样流式传输的大文件。

那么,有什么解决办法呢?这取决于发生了什么。

修复1:只是..重新打开

如果您正在读取的任何流都可以随意重新创建(例如:您可以关闭此缓冲阅读器并再次调用Files.newBufferedReader,没问题 - 如果文件是您从中获取它的地方) - 然后这样做。

修复2:完全缓存

也许您知道传入的数据相对较小。假设它也相对较快地发送,一个简单的解决方案是将其全部读入,然后您可以反复重新流式传输内存中的内容。例如:

String data;
try (var in = someSocket.getInputStream()) {
data = new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
// now you can do this as many times as you want:
BufferedReader br = new BufferedReader(new StringReader(data));

修复3:将副本流式传输到磁盘

您还可以编写代码,将读取的所有内容保存到磁盘,同时处理所有内容。假设您遍历了整个输入,然后想要再次遍历它,请打开文件进行第二次运行。

修复4:忘记缓冲阅读器

如果您只是在读取文件,则不需要 BufferedReader,这是一个基本上不包括随意重启的抽象。 可以要求FileChannelRandomAccessFile对象将其位置重置为 0。请注意,它们对字节进行操作,而不是对字符进行操作。如果其中的数据是随机宽度的字符格式(例如非常常见的 UTF-8),则尤其成问题。

修复5:有限的倒带

BufferedReader 确实支持有限的倒带功能,该功能只是通过将最后 X 个字节读入内存来实现的。这就是"标记"系统。您必须规定内存缓冲区的最大大小,当您这样做时,BufferedReader 对象立即创建该大小的缓冲区。因此,在读取 1GB 文件时,您可以打开阅读器,为 1GB 的数据设置标记,开始读取,现在您可以随意重置。但请注意,这会立即将 JVM 的内存占用量增加 1GB,并且不能用于节省超过 2GB 的内存(因为 java 不允许你使数组大于此)。

看起来像这样:

try (BufferedReader br = howeverYouGetIt()) {
// let's reread the stream 100 times!
for (int i = 0; i < 100; i++) {
if (i > 0) br.reset(); // don't reset the first time.
br.mark(1234567); // how large should it be?
// code that reads goes here
}
}

修复6:重新构想算法

假设您需要回到起点的唯一原因是为了一个相对简单的细节。比如说,该文件是一个非常长的名字列表,您实际上需要再次浏览它只是将名称"Jane"在列表中出现的次数相加。然后,也许你想只是..数一数这些名字,现在根本不需要重新启动:

Map<String, Integer> nameCounts = new HashMap<>();
try (var br = howeverYouGetYourBufferedReader()) {
while (true) {
String name = br.readLine();
int count = nameCounts.getOrDefault(name, 0);
nameCounts.put(name, count + 1);
if (name.equals("Joe")) {
// let's say you want to go back and count all
// janes read so far when this happens...
int countOfJanes = nameCounts.get("Jane");
}
}
}

大约 50 种其他选项浮现在脑海中,但您肯定明白了。

您可以使用 BufferedReader

  1. 首先,将文件放入 BufferedReader 中

    BufferedReaderreader = new BufferedReader(new FileReader("src/main/resources/input.txt"));

  2. 二、阅读所有行

    public String readAllLines(BufferedReader reader) 抛出 IOException { StringBuilder content = new StringBuilder(); 字符串线;

    while ((line = reader.readLine()) != null) {
    content.append(line);
    content.append(System.lineSeparator());
    }
    return content.toString();
    

    }

祝你好运!

最新更新