清理Java8流后

时间:2016-12-14 18:06:27

标签: java stream java-8 java-stream

当我从一个无界的Stream开始并使用limit()方法对其进行绑定时,如何在达到限制时清理Stream使用的资源?例如,如果我正在尝试使用Files.lines方法执行的操作,但使用浮点数而不是字符串,我会编写一个看起来像这样的函数:

public static Stream<Float> floats(File f) throws FileNotFoundException {
        FileInputStream fis = new FileInputStream(f);
        return Stream.generate(() -> {

            byte[] buff = new byte[4];
            try { fis.read(buff); }
            catch (Exception e) { e.printStackTrace(); }
            return ByteBuffer.wrap(buff).getFloat(0);

        }).limit(f.length()/4);
    }

这应该流式传输一个充满浮动的大型二进制文件,直到我到达文件的末尾。我将文件的长度除以构成浮点数的四个字节的字节数。但是,一旦达到此限制,我想找到一些方法来执行fis.close()。 Streams API是否有任何方法可以让您这样做?

2 个答案:

答案 0 :(得分:0)

我想出了另一种可能性。这是一种黑客行为,但似乎有效。我只是通过一个总是返回true的过滤器来运行Stream,但是在这样做的过程中,它会检查EOF并在达到输入流时关闭它。我希望有更简洁的方法来构建API。

    Stream<Float> answer;
    FileInputStream fis = new FileInputStream(f);

    answer = Stream
            .generate(() -> {
                byte[] buff = new byte[4];
                try { fis.read(buff); }
                catch (Exception e) { e.printStackTrace(); }
                return ByteBuffer.wrap(buff).getFloat(0);})
            .filter(x -> { 
                try { if (fis.available() == 0) fis.close(); } 
                catch (Exception e) { e.printStackTrace(); }
                return true;})
            .limit(f.length()/4);

    return answer;

答案 1 :(得分:0)

我会使用完全不同的方法:

public static Stream<Float> floats(File f) throws FileNotFoundException {
    try(FileChannel fch = FileChannel.open(f.toPath(), StandardOpenOption.READ)) {
        ByteBuffer  bb = fch.map(FileChannel.MapMode.READ_ONLY, 0, fch.size());
        FloatBuffer fb = bb.asFloatBuffer();
        return IntStream.range(0, fb.remaining()).mapToObj(fb::get);
    }
    catch(IOException ex) { // or consider to declare "throws IOException" instead
        FileNotFoundException fnfe = new FileNotFoundException(ex.getMessage());
        fnfe.initCause(ex);
        throw fnfe;
    }
}

这样,当方法返回时FileChannel已经关闭。它也可能更有效率。请注意,对于大量操作,将数据处理为DoubleStream可能更有效,即使源值为float并且只将最终结果的类型缩小回{{1} },如有必要:

float

此外,您可以考虑直接使用public static DoubleStream floatsAsDouble(File f) throws FileNotFoundException { try(FileChannel fch = FileChannel.open(f.toPath(), StandardOpenOption.READ)) { ByteBuffer bb = fch.map(FileChannel.MapMode.READ_ONLY, 0, fch.size()); FloatBuffer fb = bb.asFloatBuffer(); return IntStream.range(0, fb.remaining()).mapToDouble(fb::get); } catch(IOException ex) { // or consider to declare throwsIOException instead FileNotFoundException fnfe = new FileNotFoundException(ex.getMessage()); fnfe.initCause(ex); throw fnfe; } } … float sum=(float)floatsAsDouble(new File("path")).sum(); 而不是Path