有 Java 编程相关的问题?

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

java从InputStream读取到OutputStream的最快方式

下面的代码以1.3秒的速度传输2.43 MB文件

byte[] buff = new byte[64*1024];

private static void flow(InputStream is, OutputStream os, byte[] buf )
        throws IOException {
    int numRead;
    while ( (numRead = is.read(buf) ) >= 0) {
        os.write(buf, 0, numRead);
    }
}

InputStream流式传输到OutputStream的最快方式是什么

更新:

数据源是一个缓存,具体来说是EHCache:

byte[] cached = cacheService.get(cacheKey); // Just `2 ms` to get the bytes, very fast
if(cached != null && cached.length > 0) {
    flow(ByteSource.wrap(cached).openStream(), outputStream, buff);
}

共 (3) 个答案

  1. # 1 楼答案

    我不能断言它是最快的,但我建议使用apache-commons-ioIOUtils。特别是

    public static long copy(InputStream input, OutputStream output, int bufferSize)
    

    并尝试使用不同的bufferSize值进行基准测试

    https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/IOUtils.html#copy(java.io.InputStream,%20java.io.OutputStream,%20int)

    这里真正的问题是您正在处理的高级别抽象。如果您确切地知道数据来自何处(例如文件系统)及其去向(例如网络套接字),并且您知道正在使用哪个操作系统,那么就可以利用内核的流支持来加快速度

    在谷歌上搜索“零拷贝内核io”,我发现了这篇文章,它是一个不错的概述: https://xunnanxu.github.io/2016/09/10/It-s-all-about-buffers-zero-copy-mmap-and-Java-NIO/

  2. # 2 楼答案

    由于Java 9,InputStream提供了一个transferTo(OutStream)方法,也可以使用Java 7 Files。 同样,也没有关于哪一个是最快的,但你也可以对它们进行基准测试

    参考资料:

    1. Official Documentation
    2. A similar Question
  3. # 3 楼答案

    我也会说commons io:IOUtils::copy这可能比简单的方法做得更好,但代码似乎与您的代码做得一样(请参见copyLarge),但关于Java 9的答案使它成为一个更好的选择

    public static long copyLarge(final InputStream input, final OutputStream output, final byte[] buffer)
            throws IOException {
        long count = 0;
        int n;
        while (EOF != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        return count;
    }
    

    然而,您的问题可能不是如何复制,而是缺少缓冲:您可以尝试在现有流的基础上使用BufferedInputStreamBufferedOutputStream

    • Files.newInputStream未被缓冲
    • Files.newOutputStream未被缓冲
    • 你可以使用FileChannelByteBuffer
    • 系统可能正在缓冲文件

    您应该进行JMH基准测试:

    • 不确定如何禁用系统缓冲。我不认为这是个问题
    • 我会首先用不同大小的缓冲输入流(8K、16K、32K、64K、512K、1M、2M、4M、8M)检查结果
    • 然后使用缓冲输出流
    • 然后混合两种

    虽然执行可能需要时间,但通往最快的的道路意味着测量