Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Path Stream and FileSystemException (Too many open files)

Tags:

java-8

nio

geniuses!

I'm practicing Java 8.

So if I do something like this:

Files.walk(Paths.get(corpusPathStr))
        .filter(path -> path.toFile().isFile())
        .forEach(path -> {
            try {
                Files.lines(path)
                        .forEach(...);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

I got FileSystemException error.

If I open a file under forEach, may too many files be opened?

Or are there other reasons causing FileSystemException (Too many open files)?

Thanks for your help in advance!

like image 857
ghchoi Avatar asked Mar 28 '17 10:03

ghchoi


2 Answers

Use

try(Stream<Path> stream = Files.walk(Paths.get(corpusPathStr))) {
    stream.filter(path -> Files.isRegularFile(path) && Files.isReadable(path))
          .flatMap(path -> {
                       try { return Files.lines(path); }
                       catch (IOException e) { throw new UncheckedIOException(e); }
                   })
          .forEach(...);
}
catch(UncheckedIOException ex) {
    throw ex.getCause();
}

The streams returned by Files.walk and Files.lines must be properly closed to release the resources, which you do by either, a try(…) construct or returning them in the mapping function of a flatMap operation.

Don’t use nested forEachs.

The UncheckedIOException might not only be thrown by our mapping function, but also the stream implementations. Translating it back to an IOException allows to treat them all equally.

like image 121
Holger Avatar answered Nov 17 '22 19:11

Holger


Files::line opens and reads the file in a lazy manner, i.e. Stream<String>. Since you're not closing any of your opened Streams you're getting such an error.

So when you're done reading a file you should close its handle. Since the returned Stream is AutoCloseable you can and should use a try-with-resource block.

try (Stream<Path> walk = Files.walk(Paths.get(""))) {
  walk.filter(Files::isRegularFile).forEach(path -> {
    try (Stream<String> lines = Files.lines(path)) {
      lines.forEach(System.out::println);
    } catch (IOException e) {
      e.printStackTrace();
    }
  });
} catch (IOException e) {
  e.printStackTrace();
}
like image 7
Flown Avatar answered Nov 17 '22 19:11

Flown