java - ChannelInputStream 跳过方法很慢

标签 java nio

我有以下一段测试代码:

    try {
        InputStream is;
        Stopwatch.start("FileInputStream");
        is = new FileInputStream(imageFile.toFile());
        is.skip(1024*1024*1024);
        is.close();
        Stopwatch.stop();

        Stopwatch.start("Files.newInputStream");
        is = Files.newInputStream(imageFile);
        is.skip(1024*1024*1024);
        is.close();
        Stopwatch.stop();
    }
    catch(Exception e)
    {

    }

我有以下输出:

Start: FileInputStream
FileInputStream : 0 ms
Start: Files.newInputStream
Files.newInputStream : 3469 ms

你知道发生了什么事吗?为什么在第二种情况下 skip 这么慢?

我需要使用从 channel 获取的 InputStreams,因为我的测试表明最适合我的任务是让两个线程同时从文件中读取(并且只有当我使用来自 channel 的流时我才能注意到任何改进)。

在测试期间我发现我可以做这样的事情:

    SeekableByteChannel sbc = Files.newByteChannel(imageFile);
    sbc.position(1024*1024*1024);
    is = Channels.newInputStream(sbc);

这只需要平均。 28 毫秒,但这对我帮助不大,因为要使用它,我必须对 API 进行重大更改。

我的平台:

Linux galileo 3.11.0-13-generic #20-Ubuntu SMP Wed Oct 23 07:38:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

最佳答案

查看源代码,似乎 skip() 的默认实现实际上是读取(并丢弃)流内容,直到它到达目标位置:

public long skip(long n) throws IOException {
    long remaining = n;
    int nr;

    if (n <= 0) {
        return 0;
    }

    int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
    byte[] skipBuffer = new byte[size];
    while (remaining > 0) {
        nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
        if (nr < 0) {
            break;
        }
        remaining -= nr;
    }

    return n - remaining;
}

SeekableByteChannel#position() 方法可能只是更新一个偏移指针,实际上不需要任何 I/O。据推测,FileInputStream 用类似的优化覆盖了 skip() 方法。文档支持这一理论:

This method may skip more bytes than are remaining in the backing file. This produces no exception and the number of bytes skipped may include some number of bytes that were beyond the EOF of the backing file. Attempting to read from the stream after skipping past the end will result in -1 indicating the end of the file.

在拼盘磁盘或网络存储上,这可能会产生重大影响。

关于java - ChannelInputStream 跳过方法很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20056748/

相关文章:

java - 在 Java 中是否有任何生产就绪的方法来检查/强制执行某种函数纯度?

java - 无法在弹出式 JFrame 中编辑 JTextField

java - 创建新对象的 ByteBuddy 方法实现

java - 在 Java 中将泛型类型与枚举相关联

java - 尝试运行 Java 多线程服务器时出现空指针异常

java - 有什么办法可以连接两个 channel 吗?

java - 创建 Java NIO 文件系统时, "env"选项(及其用途)是什么?

java - Java NIO 是否支持广播或多播?

java - 下游事件在jboss的netty中是如何工作的?

java - 如何从 java.nio.Path 获取路径字符串?