当我从一个无界的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是否有任何方法可以让您这样做?
答案 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
。