如何克隆输入流?

2022-08-31 06:28:06

我有一个输入流,我传递给一个方法来做一些处理。我将在其他方法中使用相同的 InputStream,但在首次处理后,输入流似乎在方法内部关闭。

如何克隆输入流以发送到关闭他的方法?还有另一种解决方案?

编辑:关闭输入流的方法来自 lib 的外部方法。我无法控制关闭与否。

private String getContent(HttpURLConnection con) {
    InputStream content = null;
    String charset = "";
    try {
        content = con.getInputStream();
        CloseShieldInputStream csContent = new CloseShieldInputStream(content);
        charset = getCharset(csContent);            
        return  IOUtils.toString(content,charset);
    } catch (Exception e) {
        System.out.println("Error downloading page: " + e);
        return null;
    }
}

private String getCharset(InputStream content) {
    try {
        Source parser = new Source(content);
        return parser.getEncoding();
    } catch (Exception e) {
        System.out.println("Error determining charset: " + e);
        return "UTF-8";
    }
}

答案 1

如果您只想多次读取相同的信息,并且输入数据足够小以容纳内存,则可以将数据从您的复制到ByteArrayOutputStreamInputStream

然后,您可以获取关联的字节数组,并根据需要打开任意数量的“克隆”ByteArrayInputStream

ByteArrayOutputStream baos = new ByteArrayOutputStream();

// Code simulating the copy
// You could alternatively use NIO
// And please, unlike me, do something about the Exceptions :D
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1 ) {
    baos.write(buffer, 0, len);
}
baos.flush();
    
// Open new InputStreams using recorded bytes
// Can be repeated as many times as you wish
InputStream is1 = new ByteArrayInputStream(baos.toByteArray()); 
InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); 

但是,如果您确实需要保持原始流打开以接收新数据,则需要跟踪对 的外部调用。您将需要防止以某种方式被调用。close()close()

更新(2019):

从Java 9开始,中间位可以用InputStream.transferTo替换:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
input.transferTo(baos);
InputStream firstClone = new ByteArrayInputStream(baos.toByteArray()); 
InputStream secondClone = new ByteArrayInputStream(baos.toByteArray()); 

答案 2

你想使用Apache的CloseShieldInputStream

这是一个包装器,可防止流被关闭。你会做这样的事情。

InputStream is = null;

is = getStream(); //obtain the stream 
CloseShieldInputStream csis = new CloseShieldInputStream(is);

// call the bad function that does things it shouldn't
badFunction(csis);

// happiness follows: do something with the original input stream
is.read();