Java Stream BufferedReader文件流

时间:2015-05-11 06:17:38

标签: java-8 bufferedreader java-stream

我正在使用Java 8 Streams从csv文件创建流。 我正在使用BufferedReader.lines(),我阅读了BufferedReader.lines()的文档:

  

执行终端流操作后,无法保证读者将处于读取下一个字符或行的特定位置。

public class Streamy {
    public static void main(String args[]) {
        Reader reader = null;
        BufferedReader breader = null;
        try {
            reader = new FileReader("refined.csv");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        breader = new BufferedReader(reader);
        long l1 = breader.lines().count();
        System.out.println("Line Count " + l1); // this works correctly

        long l2 = breader.lines().count();
        System.out.println("Line Count " + l2); // this gives 0
    }
}

看起来第一次读取文件后,读者无法访问文件的开头。解决这个问题的方法是什么

3 个答案:

答案 0 :(得分:7)

  

看起来第一次读取文件后,读者无法进入文件的开头。

不 - 而且我不知道为什么你会期望它给你引用的文件。基本上,lines()方法在开始之前不会“回放”阅读器,甚至可能无法进行。 (想象一下,BufferedReader包裹了一个包裹网络连接InputStreamReader的{​​{1}} - 一旦您读取了数据,它就消失了。)

  

解决此问题的方法是什么

两个选项:

  • 重新打开文件并从头开始阅读
  • InputStream的结果保存到lines(),这样您就不会第二次读取该文件了。例如:

    List<String>

顺便说一句,我强烈建议使用List<String> lines = breader.lines().collect(Collectors.toList()); 代替Files.newBufferedReader - 后者始终使用平台默认编码,这通常不是一个好主意

就此而言,要将所有行加载到列表中,如果您希望将行作为流而不是列表,则可以使用Files.readAllLines ...或Files.lines。 (但请注意评论中的警告。)

答案 1 :(得分:1)

可能需要澄清来自JavaDoc的引用片段。通常你会期望在阅读完整个文件后,读者会指向文件的末尾。但是使用流取决于是否使用短路终端操作以及流是否是并行的。例如,如果您使用

String magicLine = breader.lines()
    .filter(str -> str.startsWith("magic"))
    .findAny()
    .orElse(null);

您的读者可能会在第一个找到的行之后停止(因为无需进一步阅读)或读取整个输入文件(如果找不到这样的行)。如果在并行流中进行相同的操作,则结果位置将是不可预测的,因为输入将被拆分为一些依赖于实现的块,其中将执行搜索。这就是它在文档中以这种方式编写的原因。

至于解决方法,请阅读@JonSkeet答案。并考虑通过try-with-resource构造来关闭你的流。

答案 2 :(得分:0)

如果无法保证读者会在某一特定行,那为什么不创建两个读者?

 reader1=new FileReader("refined.csv");
 reader2=new FileReader("refined.csv");