我正在减少InputStreams
的流,如此:
InputStream total = input.collect(
Collectors.reducing(
empty,
Item::getInputStream,
(is1, is2) -> new SequenceInputStream(is1, is2)));
对于身份InputStream
,我正在使用:
InputStream empty = new ByteArrayInputStream(new byte[0]);
这样可行,但是有更好的方法来表示空的InputStream
吗?
答案 0 :(得分:12)
由于InputStream
只有一个抽象方法,read()
,
public abstract int read() throws IOException
<强>返回:强>
数据的下一个字节,如果到达流的末尾,则为-1
。
anonymous subclass很容易创建一个空流。 像这样:
InputStream empty = new InputStream() {
@Override
public int read() {
return -1; // end of stream
}
};
但不可否认,它的代码多于空ByteArrayInputStream
。
答案 1 :(得分:3)
我会走另一条路。
通过InputStream
减少大量(is1, is2) -> new SequenceInputStream(is1, is2)
个实例可能会造成SequenceInputStream
个实例的深度不平衡树,这可能会变得非常低效。
线性数据结构更合适:
InputStream total = new SequenceInputStream(
Collections.enumeration(input.map(Item::getInputStream).collect(Collectors.toList())));
这会创建一个SequenceInputStream
处理所有收集的输入流。由于这本身也处理空列表情况,因此不再需要特殊的空InputStream
实现。
但是当你看the source code of SequenceInputStream
时,你会发现这个课程毫无魔力,事实上,我们甚至可以通过不使用Vector
和Enumeration
之类的古老课程来做得更好:
public class StreamInputStream extends InputStream {
final Spliterator<? extends InputStream> source;
final Consumer<InputStream> c = is -> in = Objects.requireNonNull(is);
InputStream in;
public StreamInputStream(Stream<? extends InputStream> sourceStream) {
(source = sourceStream.spliterator()).tryAdvance(c);
}
public StreamInputStream(InputStream first, InputStream second) {
this(Stream.of(first, second));
}
public int available() throws IOException {
return in == null? 0: in.available();
}
public int read() throws IOException {
if(in == null) return -1;
int b; do b = in.read(); while(b<0 && next());
return b;
}
public int read(byte b[], int off, int len) throws IOException {
if((off|len) < 0 || len > b.length - off) throw new IndexOutOfBoundsException();
if(in == null) return -1; else if(len == 0) return 0;
int n; do n = in.read(b, off, len); while(n<0 && next());
return n;
}
public void close() throws IOException {
closeCurrent();
}
private boolean next() throws IOException {
closeCurrent();
return source.tryAdvance(c);
}
private void closeCurrent() throws IOException {
if(in != null) try { in.close(); } finally { in = null; }
}
}
除了更简单和更清晰(它不需要catch (IOException ex) { throw new Error("panic"); }
之类的语句)之外,它还考虑了流的惰性:当在遍历所有元素之前关闭它时,它不会遍历剩余的流来关闭InputStream
元素,因为它们通常甚至不会在此时创建,因此不需要关闭。
现在,流的创建就像
一样简单InputStream total = new StreamInputStream(input.map(Item::getInputStream));
答案 2 :(得分:3)
从Java 11开始,您可以使用静态方法InputStream.nullInputStream()
:
返回不读取字节的新InputStream。返回的流最初是打开的。通过调用close()方法关闭流。随后对close()的调用无效。
答案 3 :(得分:0)
如果您的项目中有 Apache commons-io
:
import org.apache.commons.io.IOUtils
IOUtils.toInputStream("")