In a Nutshell.

[Kotlin, FOSS, Developer's Life.]

Вы все еще используете Files.lines()?

Привет, и в очередной раз мы поговорим про новшества Java 8, а точнее Files.lines().

Что может быть проще:

public class FilesLines {

    public static void main(String[] args) throws Exception {

        Path path = Paths.get("/home/ruslan/test.txt");

        for (int i = 0; i < 10000; i++) {
            Files.lines(path).count();
        }
    }
}

Создаем стринговый стрим из файла делаем какие-то операции со стримом и продолжаем работу, стрим же сам о всем позаботиться.

Запустим этот код под Ubuntu 14.04

java -version
java version "1.8.0_31"
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)

Результат:

Exception in thread "main" java.nio.file.FileSystemException: /home/ruslan/test.txt: Too many open files
    at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
    at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
    at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
    at java.nio.file.Files.newByteChannel(Files.java:361)
    at java.nio.file.Files.newByteChannel(Files.java:407)
    at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
    at java.nio.file.Files.newInputStream(Files.java:152)
    at java.nio.file.Files.newBufferedReader(Files.java:2784)
    at java.nio.file.Files.lines(Files.java:3744)
    at java.nio.file.Files.lines(Files.java:3785)
    at by.ibragimov.jpress.FilesLines.main(FilesLines.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

WTF

Что-же говорит нам документация? Посмотрим: File#lines(Path path) не содержит ничего подозрительного, но внутри просто делегирует вызов в Files#lines(Path path, Charset cs), а вот тут уже JavaDoc’и на намекают:

/**
 * ...
 * The returned stream encapsulates a {@link Reader}.  If timely
 * disposal of file system resources is required, the try-with-resources
 * construct should be used to ensure that the stream's
 * {@link Stream#close close} method is invoked after the stream operations
 * are completed.
 * ...
 */

Ну и исправленная версия напоследок:

public class FilesLines {

    public static void main(String[] args) throws Exception {

        Path path = Paths.get("/home/ruslan/test.txt");

        for (int i = 0; i < 10000; i++) {
            try(Stream<String> stream = Files.lines(path)) {
                stream.count();
            }
        }
    }
}

Вывод как всегда один: читайте документацию.

comments powered by Disqus