gpt4 book ai didi

Java8 Stream 的文件,如何控制文件的关闭?

转载 作者:搜寻专家 更新时间:2023-10-31 19:37:00 24 4
gpt4 key购买 nike

假设我有一个 Java8 Stream<FileReader>并且我将该流用于 map等等,我怎样才能控制 FileReader 的关闭? s 在流中使用了吗?

请注意,我可能无法访问个人 FileReader例如:

filenames.map(File::new)
.filter(File::exists)
.map(f->{
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(f));
} catch(Exception e) {}
return Optional.ofNullable(br);
})
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(...something that reads the file contents...) // From here, the Stream doesn't content something that gives access to the FileReaders

在做了一些其他映射等之后,我终于失去了 FileReader在续集中。

我最初认为垃圾收集器能够在需要时执行此操作,但我在 filenames 时遇到了操作系统描述符耗尽的情况。是长Stream .

最佳答案

关于使用 FileReader 的一般说明:FileReader 在内部使用一个 FileInputStream,它覆盖 finalize(),因此是 discouraged to use因为它对垃圾收集有影响,尤其是在处理大量文件时。

除非您使用的是 Java 7 之前的 Java 版本,否则您应该改用 java.nio.files API,创建一个 BufferedReader

 Path path = Paths.get(filename);
BufferedReader br = Files.newBufferedReader(path);

所以你的流管道的开始应该看起来更像

 filenames.map(Paths::get)
.filter(Files::exists)
.map(p -> {
try {
return Optional.of(Files.newBufferedReader(p));
} catch (IOException e) {
return Optional.empty();
}
})

现在解决你的问题:

选项1

保留原始 Reader 的一种方法是使用元组。元组(或其任何 n 元变体)通常是处理函数应用程序的多个结果的好方法,就像在流管道中完成的那样:

class ReaderTuple<T> {
final Reader first;
final T second;
ReaderTuple(Reader r, T s){
first = r;
second = s;
}
}

现在您可以将 FileReader 映射到一个元组,其中第二个项目是您当前的流项目:

 filenames.map(Paths::get)
.filter(Files::exists)
.map(p -> {
try {
return Optional.of(Files.newBufferedReader(p));
} catch (IOException e) {
return Optional.empty();
}
})
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(r -> new ReaderTuple(r, yourOtherItem))
....
.peek(rt -> {
try {
rt.first.close() //close the reader or use a try-with-resources
} catch(Exception e){}
})
...

该方法的问题在于,无论何时在 flatMap 和 peek 之间的流执行期间发生未经检查的异常,读取器都可能不会关闭。

选项 2

使用元组的另一种方法是将需要读取器的代码放在 try-with-resources block 中。这种方法的优点是您可以控制关​​闭所有阅读器。

示例 1:

 filenames.map(Paths::get)
.filter(Files::exists)
.map(p -> {
try (Reader r = new BufferedReader(new FileReader(p))){

Stream.of(r)
.... //put here your stream code that uses the stream

} catch (IOException e) {
return Optional.empty();
}
}) //reader is implicitly closed here
.... //terminal operation here

示例 2:

filenames.map(Paths::get)
.filter(Files::exists)
.map(p -> {
try {
return Optional.of(Files.newBufferedReader(p));
} catch (IOException e) {
return Optional.empty();
}
})
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(reader -> {
try(Reader r = reader) {

//read from your reader here and return the items to flatten

} //reader is implicitly closed here
})

示例 1 的优点是读者肯定会关闭。示例 2 是安全的,除非您在创建读取器和可能会失败的 try-with-resources block 之间放置更多内容。

我个人会选择示例 1,并将访问读取器的代码放在一个单独的函数中,这样代码可读性更好。

关于Java8 Stream 的文件,如何控制文件的关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43504078/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com