当前位置: 首页 > 面试题库 >

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

阎淮晨
2023-03-14
问题内容

假设我有一个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它很长时,我已经经历了OS描述符耗尽Stream


问题答案:

关于使用FileReader的一般注意事项:FileReader在内部使用FileInputStream,它会覆盖finalize()并且因此不建议使用它对垃圾回收的影响,尤其是在处理大量文件时。

除非您使用的是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块中。这种方法的优势在于您可以控制所有读者。

范例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块之间添加更多内容,否则可能会失败。

我个人将使用示例1,并将访问读者的代码放在单独的函数中,以使代码更易读。



 类似资料:
  • 有没有办法使用hadoop流作业将这20,000个文件合并到10,000个文件?或者,换句话说,有没有办法控制hadoop流式输出文件的数量? 提前感谢!

  • null 但是,如何和在哪里配置它呢?

  • 问题内容: 我正在尝试在python中找到一种将脚本执行日志重定向到文件以及以pythonic方式的方法。有没有简单的方法可以做到这一点? 问题答案: 我想出了这个[unested] 在python中将期望有一个函数。您可以使用具有此功能的自定义对象。否则,您也可以让sys.stdout引用您的对象,在这种情况下,即使没有,它也会被准备。

  • 谁能告诉我如何在android中组合图像并生成一个mp4文件,并将视频文件存储在SDCard中?

  • 问题内容: 我将所有AngularJS控制器都放在一个文件controllers.js中。该文件的结构如下: 我想做的是将Ctrl1和Ctrl2放入单独的文件中。然后,我会将这两个文件都包含在index.html中,但是应该如何构造呢?我尝试做这样的事情,它在网络浏览器控制台中引发错误,提示找不到控制器。有什么提示吗? 问题答案: 文件一: 文件二: 文件三: 按该顺序包括。我推荐3个文件,因此模

  • 我的所有AngularJS控制器都在一个文件controllers.js中。该文件的结构如下: 我想做的是将Ctrl1和Ctrl2放入单独的文件中。然后,我会在index.html中包含这两个文件,但该如何结构化呢?我试着做这样的事情,它在web浏览器控制台中抛出一个错误,说它找不到我的控制器。有什么提示吗? 我搜索了StackOverflow并发现了这个类似的问题--然而,这个语法在Angula