使用Java中的Files.lines读取文件的第一行

5
我想要使用这个代码只读取文件的第一行:
String line = Files.lines(path).findFirst().get();

我认为这种方法不会将整个文件的内容加载到内存中,而是打开文件,只读取第一行内容,然后关闭文件。

我的假设是正确的吗?


将File-IO标签添加到标签中,使标签更具体。 - Hovercraft Full Of Eels
2个回答

7

来自文件Javadoc:

static Stream lines(Path path) - 将文件中的所有行读取为流。

Files.lines(path) 会读取所有行,这意味着它们有可能被访问,但是加载到内存中的内容取决于流所需的内容。在你的情况下,只有第一行将被访问(存储在内存中),因为BufferedReader能够按需惰性地加载内容到内存中。


6
Files#lines 方法使用 BufferedReader 类来访问行,使用 BufferedReader#lines 来获取行。从 源代码 可知:

返回一个流,其元素是从此 BufferedReader 中读取的行。java.util.stream.Stream 是惰性填充的,即只有在终端流操作期间才会进行读取。不能在执行终端流操作期间对读取器进行操作。否则,终端流操作的结果是未定义的。

执行终端流操作后,不能保证读取器将处于特定位置以读取下一个字符或行。

如果访问底层 BufferedReader 时抛出 IOException,则将其包装在 UncheckedIOException 中,并将从导致读取发生的 Stream 方法中抛出。如果在关闭 BufferedReader 后调用此方法,则该方法将返回一个 Stream。在 BufferedReader 关闭后需要从中读取的任何操作都将导致抛出 UncheckedIOException。

public Stream<String> lines() {
    Iterator<String> iter = new Iterator<String>() {
        String nextLine = null;

        @Override
        public boolean hasNext() {
            if (nextLine != null) {
                return true;
            } else {
                try {
                    nextLine = readLine();
                    return (nextLine != null);
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }
        }

        @Override
        public String next() {
            if (nextLine != null || hasNext()) {
                String line = nextLine;
                nextLine = null;
                return line;
            } else {
                throw new NoSuchElementException();
            }
        }
    };
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
}
StreamSupport.stream创建的Stream是由一个Iterator支持的。因为你调用了Stream#findFirst,所以只要求一个元素。因此,仅调用一次hasNextnext,这意味着BufferedReader#readLine仅被调用一次。请保留HTML标记。

所以如果它是一个BufferedReader,那么它只会读取必要的内容,对于我的情况来说,这将是一行,然后关闭读取器,对吗?(当然,如果我继续消耗流,则会读取剩余部分)。 - stepanian
你的回答似乎与 @Matt 的回答相矛盾。我应该相信谁?哈哈 - stepanian
@stepanian 我们并不矛盾!Matt说你可以加载所有内存。我会发布更多代码来突出显示。 - flakes
@flakes Matt几乎完全改变了他的答案 :) - stepanian
@stepanian 对于内存中的潜在加载和实际加载,我应该更加注意,抱歉。 - Matt Goodrich
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接