2017-10-11 382 views
0

Java 8的流API已经很方便并且很受欢迎。对于文件I/O,我发现提供了两个API来生成流输出:Files.lines(path)bufferedReader.lines();Java 8的Files.lines():对于很长的行的性能问题

虽然我没有找到提供固定大小的缓冲区读取文件流的流API。

我的问题是:如果文件的行很长,例如只有一行的4GB文件,是不是这些基于行的API非常低效?

基于行的阅读器至少需要4GB内存来保持该行。 与固定大小的缓冲区读取器(fileInputStream.read(byte[] b, int off, int len))相比,最多占用内存的缓冲区大小。

如果上述问题属实,是否有任何Stream API for file I/O API更高效?

+3

'Files.lines(path)'和'bufferedReader.lines() '是为了读取字符/字符串,而'InputStream :: read'方法用于读取字节。我不知道你的问题在哪里。 – Flown

+1

如果输入是基于行的,并且一个Stream链可以单独处理每一行,那么相同的数据如何在固定大小的块中处理? – Andreas

回答

2

这取决于您希望如何处理数据,哪种交付方式是适当的。因此,如果您的处理要求逐行处理数据,则无法这样做。

如果你真的想要的字符数据的固定大小的块,你可以使用下面的方法(S):

public static Stream<String> chunks(Path path, int chunkSize) throws IOException { 
    return chunks(path, chunkSize, StandardCharsets.UTF_8); 
} 
public static Stream<String> chunks(Path path, int chunkSize, Charset cs) 
throws IOException { 
    Objects.requireNonNull(path); 
    Objects.requireNonNull(cs); 
    if(chunkSize<=0) throw new IllegalArgumentException(); 

    CharBuffer cb = CharBuffer.allocate(chunkSize); 
    BufferedReader r = Files.newBufferedReader(path, cs); 
    return StreamSupport.stream(
     new Spliterators.AbstractSpliterator<String>(
      Files.size(path)/chunkSize, Spliterator.ORDERED|Spliterator.NONNULL) { 
      @Override public boolean tryAdvance(Consumer<? super String> action) { 
       try { do {} while(cb.hasRemaining() && r.read(cb)>0); } 
       catch (IOException ex) { throw new UncheckedIOException(ex); } 
       if(cb.position()==0) return false; 
       action.accept(cb.flip().toString()); 
       return true; 
      } 
    }, false).onClose(() -> { 
     try { r.close(); } catch(IOException ex) { throw new UncheckedIOException(ex); } 
    }); 
} 

,但如果你的下一个问题是“我怎么能合并相邻的我也不会感到惊讶流元素“,因为这些固定大小的块很少是实际任务的自然数据单元。

通常情况下,接下来的步骤是在内容中执行模式匹配,在这种情况下,首先使用Scanner比较好,它可以在流式传输数据时执行模式匹配,可以完成因为正则表达式引擎会告诉您缓冲更多数据是否会改变匹配操作的结果(请参阅hitEnd()requireEnd())。不幸的是,仅从Scanner生成的匹配流才被添加到Java 9中,但请参阅this answer,以获得该功能的后端端口到Java 8的功能。

+0

谢谢。我正在寻找编写我自己的流生成API的入门指南。我认为这个答案是一个正确的起点。我还没有找到找到相邻元素的阶段。但是,当它出现在图片中时,有一个标志可以找到它的位置。 – modeller

4

如果您的文本文件只有一行,并且您正在逐行处理它,那么由于不了解您正在使用的数据,您在编程中犯了严重错误。

当您需要使用CSV或其他此类格式的数据进行简单的工作时,这些便利的方法是可行的,并且线路尺寸可管理。

带有单行的4GB文本文件的实际示例应该是没有换行符的XML文件。您可以使用流式XML解析器来读取它,而不是逐行滚动您自己的解决方案。

+0

我知道基于行的API不适合这种情况。这就是为什么我首先要求提供更好的API。你可以举一个这样的“流XML解析器”的例子与Maven的依赖? – modeller

+0

是的,StAX。您也可以查看SAX和DOM,并比较差异。 – Kayaman