Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在最短的时间内克隆java中的inputstream_Java_Clone_Inputstream_Bufferedinputstream - Fatal编程技术网

如何在最短的时间内克隆java中的inputstream

如何在最短的时间内克隆java中的inputstream,java,clone,inputstream,bufferedinputstream,Java,Clone,Inputstream,Bufferedinputstream,有人能告诉我如何在尽可能少的创建时间内克隆输入流吗?我需要多次克隆一个inputstream,以便使用多个方法来处理IS。我试过三种方法,但由于这样或那样的原因,一切都不起作用 方法#1: 多亏了stackoverflow社区,我发现下面的链接很有帮助,并将代码片段合并到我的程序中 但是,使用此代码创建克隆的inputstreams最多需要一分钟(对于10MB文件),我的程序需要尽可能快 int read = 0; byte[] bytes = new byte[1024*10

有人能告诉我如何在尽可能少的创建时间内克隆输入流吗?我需要多次克隆一个inputstream,以便使用多个方法来处理IS。我试过三种方法,但由于这样或那样的原因,一切都不起作用

方法#1: 多亏了stackoverflow社区,我发现下面的链接很有帮助,并将代码片段合并到我的程序中

但是,使用此代码创建克隆的inputstreams最多需要一分钟(对于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()。结果是真的,所以我想我可以跑了

    is1.mark() 
    is1.reset()
或者只是

    is1.reset();
在传递信息之前,请先使用我各自的方法。在上面的两个例子中,我都得到一个错误,说这是一个无效的标记

我现在没有主意了,所以提前谢谢你能给我的任何帮助

另外,从我收到的人们的评论来看,我需要澄清一些关于我的情况的事情: 1) 此程序正在VM上运行 2) inputstream正在从另一个方法传递给我。我不是在读本地文件 3) inputstream的大小未知

但是,使用此代码创建克隆的inputstreams最多需要一分钟(对于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);
复制流需要时间,而且(通常)这是克隆流的唯一方法。除非您缩小问题的范围,否则性能得到显著改善的可能性很小

以下是一些可以改进的情况:

  • 如果事先知道流中的字节数,那么可以直接读取到最终的字节数组中

  • 如果知道数据来自文件,则可以为文件创建内存映射缓冲区


但最根本的问题是移动大量字节需要时间。一个10Mb的文件(使用您问题中的代码)需要1分钟的时间,这一事实表明真正的瓶颈根本不在Java中。

您希望单独的方法并行运行还是顺序运行?如果按顺序进行,我看不到克隆输入流的理由,因此我必须假设您计划剥离线程来管理每个流


我现在不在计算机附近测试这一点,但我认为最好是以块(比如1024字节)的形式读取输入,然后将这些块(或块的数组副本)推送到输出流上,并将输入流连接到它们的线程端。如果没有可用数据,请让您的读卡器阻止,等等。

关于您的第一种方法,即将所有字节放入ByteArrayOutputStream:

  • 首先,这种方法消耗大量内存。如果您不能确保JVM在启动时分配了足够的内存,那么它将需要在处理流的过程中动态请求内存,这非常耗时
  • ByteArrayOutputStream最初是使用32字节的缓冲区创建的。每次尝试将某些内容放入其中时,如果它不适合现有的字节数组,则会创建一个新的更大的数组,并将旧字节复制到新的字节数组中。由于您每次都使用2MB输入,因此您迫使ByteArrayOutputStream将其数据一次又一次地复制到更大的数组中,每次都以2MB的大小增加其数组的大小
  • 由于旧阵列是垃圾,它们的内存很可能正在被垃圾回收器回收,这使得复制过程更加缓慢
  • 也许您应该使用指定初始缓冲区大小的构造函数来定义ByArrayOutputStream。您设置的大小越精确,过程应该越快,因为需要的中间副本就越少
第二种方法是假的,您不能在不同的其他流中修饰相同的输入流,并期望这些东西能够工作。由于字节被一个流消耗,内部流也会耗尽,无法为其他流提供准确的数据

在扩展我的答案之前,让我问一下,您的其他方法是否希望接收在单独线程上运行的输入流副本?因为如果是这样的话,这听起来像是PipedOutStream和PipedInputStream的工作

如何在尽可能少的创建时间内克隆inputstream?我需要多次克隆一个inputstream,以便使用多个方法来处理IS

您可以创建一个定制的
ReusableInputStream
类,在第一次完全读取时立即写入内部,然后在读取最后一个字节时将其包装在一个文件中,最后在随后的完全读取时重新使用相同的
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.
}

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

在我的计算机上运行方法1的代码需要18毫秒(10 MB的文件)。你的硬件有问题吗?谢谢你的回复。我认为我的硬件没有问题。我突然想到我忘了提到两件事:a)这是在虚拟机上,b)inputstream是一个jpg文件。最快的时间是11秒,但我在看我的测试