有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何克隆输入流?

我有一个InputStream,我将它传递给一个方法进行一些处理。我将在其他方法中使用相同的InputStream,但是在第一次处理之后,InputStream将在方法中关闭

我如何克隆InputStream以发送给关闭他的方法?还有别的解决办法吗

编辑:关闭InputStream的方法是库中的外部方法。我无法控制是否关门

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";
    }
}

共 (6) 个答案

  1. # 1 楼答案

    如果从流中读取的数据很大,我建议使用ApacheCommons IO中的TeInputStream。这样,您就可以复制输入,并将t’d管道作为克隆传递

  2. # 2 楼答案

    如果您只想多次读取相同的信息,并且输入数据足够小,可以将数据从InputStream复制到ByteArrayOutputStream

    然后,您可以获得相关的字节数组,并打开任意多个“克隆的”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,中间位可以替换为^{}

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    input.transferTo(baos);
    InputStream firstClone = new ByteArrayInputStream(baos.toByteArray()); 
    InputStream secondClone = new ByteArrayInputStream(baos.toByteArray()); 
    
  3. # 3 楼答案

    你不能克隆它,你将如何解决你的问题取决于数据的来源

    一种解决方案是将InputStream中的所有数据读取到字节数组中,然后围绕该字节数组创建ByteArrayInputStream,并将该输入流传递到方法中

    编辑1: 也就是说,如果另一个方法也需要读取相同的数据。即,您希望“重置”流

  4. # 4 楼答案

    这可能在所有情况下都不起作用,但我做到了:我扩展了FilterInputStream类,并在外部lib读取数据时对字节进行必要的处理

    public class StreamBytesWithExtraProcessingInputStream extends FilterInputStream {
    
        protected StreamBytesWithExtraProcessingInputStream(InputStream in) {
            super(in);
        }
    
        @Override
        public int read() throws IOException {
            int readByte = super.read();
            processByte(readByte);
            return readByte;
        }
    
        @Override
        public int read(byte[] buffer, int offset, int count) throws IOException {
            int readBytes = super.read(buffer, offset, count);
            processBytes(buffer, offset, readBytes);
            return readBytes;
        }
    
        private void processBytes(byte[] buffer, int offset, int readBytes) {
           for (int i = 0; i < readBytes; i++) {
               processByte(buffer[i + offset]);
           }
        }
    
        private void processByte(int readByte) {
           // TODO do processing here
        }
    
    }
    

    然后,您只需传递一个StreamBytesWithExtraProcessingInputStream实例,您将在其中传递输入流。使用原始输入流作为构造函数参数

    需要注意的是,这是一个字节对一个字节的操作,所以如果需要高性能,就不要使用它

  5. # 5 楼答案

    您想使用Apache的^{}

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

    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();
    
  6. # 6 楼答案

    UPD。 检查之前的评论。这不完全是被问到的

    如果您使用的是apache.commons,则可以使用IOUtils复制流

    您可以使用以下代码:

    InputStream = IOUtils.toBufferedInputStream(toCopy);
    

    以下是适合您的情况的完整示例:

    public void cloneStream() throws IOException{
        InputStream toCopy=IOUtils.toInputStream("aaa");
        InputStream dest= null;
        dest=IOUtils.toBufferedInputStream(toCopy);
        toCopy.close();
        String result = new String(IOUtils.toByteArray(dest));
        System.out.println(result);
    }
    

    此代码需要一些依赖项:

    MAVEN

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    

    GRADLE

    'commons-io:commons-io:2.4'
    

    以下是此方法的文档参考:

    Fetches entire contents of an InputStream and represent same data as result InputStream. This method is useful where,

    Source InputStream is slow. It has network resources associated, so we cannot keep it open for long time. It has network timeout associated.

    您可以在此处找到有关IOUtils的更多信息: http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#toBufferedInputStream(java.io.InputStream)