有人可以告诉我如何以尽可能少的创建时间克隆输入流吗?我需要多次克隆输入流以使用多种方法来处理IS。我已经尝试了三种方法,但由于某种原因或其他原因,事情无法正常进行。

方法1:
多亏了stackoverflow社区,我发现以下链接很有用,并将代码段合并到了我的程序中。

How to clone an InputStream?

但是,使用此代码最多可能需要一分钟(对于10MB的文件)来创建克隆的输入流,因此我的程序需要尽可能快。

    int read = 0;
    byte[] bytes = new byte[1024*1024*2];

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    while ((read = is.read(bytes)) != -1)
        bos.write(bytes,0,read);
    byte[] ba = bos.toByteArray();

    InputStream is1 = new ByteArrayInputStream(ba);
    InputStream is2 = new ByteArrayInputStream(ba);
    InputStream is3 = new ByteArrayInputStream(ba);

方法2:
我还尝试使用BufferedInputStream克隆IS。这非常快(最慢的创建时间== 1ms。最快的== 0ms)。但是,在我发送is1待处理后,处理is2和is3的方法抛出了一个错误,表明没有要处理的东西,几乎就像下面的所有3个变量都引用了相同的IS一样。
    is = getFileFromBucket(path,filename);
    ...
    ...
    InputStream is1 = new BufferedInputStream(is);
    InputStream is2 = new BufferedInputStream(is);
    InputStream is3 = new BufferedInputStream(is);

方法3:
我认为编译器在骗我。对于上面的两个示例,我检查了is1的markSupported()。它返回了true,所以我认为我可以运行
    is1.mark()
    is1.reset()

要不就
    is1.reset();

在将IS传递给我各自的方法之前。在以上两个示例中,我都收到一条错误消息,指出它是无效标记。

我现在没主意了,所以在此先感谢您能为我提供的任何帮助。

P.S.从我收到的人们的评论中,我需要澄清一些有关我的处境的事情:
1)该程序正在VM上运行
2)输入流是从另一种方法传递给我的。我不是从本地文件读取
3)输入流的大小未知

最佳答案



您可以创建某种自定义的ReusableInputStream类,在该类中,您还应在第一次完全读取时立即写入内部 ByteArrayOutputStream ,然后在读取最后一个字节时将其包装在 ByteBuffer 中,最后在后续的完全读取中重用相同的ByteBuffer当达到限制时,它会自动翻转。像第一次尝试一样,这可以使您免于一次完整的阅读。

这是一个基本的启动示例:

public class ReusableInputStream extends InputStream {

    private InputStream input;
    private ByteArrayOutputStream output;
    private ByteBuffer buffer;

    public ReusableInputStream(InputStream input) throws IOException {
        this.input = input;
        this.output = new ByteArrayOutputStream(input.available()); // Note: it's resizable anyway.
    }

    @Override
    public int read() throws IOException {
        byte[] b = new byte[1];
        read(b, 0, 1);
        return b[0];
    }

    @Override
    public int read(byte[] bytes) throws IOException {
        return read(bytes, 0, bytes.length);
    }

    @Override
    public int read(byte[] bytes, int offset, int length) throws IOException {
        if (buffer == null) {
            int read = input.read(bytes, offset, length);

            if (read <= 0) {
                input.close();
                input = null;
                buffer = ByteBuffer.wrap(output.toByteArray());
                output = null;
                return -1;
            } else {
                output.write(bytes, offset, read);
                return read;
            }
        } else {
            int read = Math.min(length, buffer.remaining());

            if (read <= 0) {
                buffer.flip();
                return -1;
            } else {
                buffer.get(bytes, offset, read);
                return read;
            }
        }

    }

    // You might want to @Override flush(), close(), etc to delegate to input.
}

(请注意,实际作业是使用int read(byte[], int, int)而不是int read()执行的,因此,当调用者本身也使用byte[]缓冲区进行流式传输时,它预计会更快)

您可以按以下方式使用它:
InputStream input = new ReusableInputStream(getFileFromBucket(path,filename));
IOUtils.copy(input, new FileOutputStream("/copy1.ext"));
IOUtils.copy(input, new FileOutputStream("/copy2.ext"));
IOUtils.copy(input, new FileOutputStream("/copy3.ext"));

至于性能,每10MB 1分钟更可能是硬件问题,而不是软件问题。我的7200rpm笔记本电脑硬盘可以在不到1秒的时间内完成操作。

09-27 21:25