我试图找出如果有任何差别性能(或者优点),当我们使用仁王 FileChannel 与正常 FileInputStream/FileOuputStream 阅读和书写的文件的文件系统。我观察到,在我的机器都执行在同一水平,还许多倍 FileChannel 的方式是速度较慢。我可以知道更多的细节比较这两种方法。这里是代码,我在使用的文件,我测试与周围是 350MB.这是一个好的选择使用仁王基于类文件I/O,如果我没看随机访问或其他这类先进的功能吗?

package trialjavaprograms;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class JavaNIOTest {
    public static void main(String[] args) throws Exception {
        useNormalIO();
        useFileChannel();
    }

    private static void useNormalIO() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        InputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        byte[] buf = new byte[64 * 1024];
        int len = 0;
        while((len = is.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.flush();
        fos.close();
        is.close();
        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }

    private static void useFileChannel() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        FileInputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        FileChannel f = is.getChannel();
        FileChannel f2 = fos.getChannel();

        ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
        long len = 0;
        while((len = f.read(buf)) != -1) {
            buf.flip();
            f2.write(buf);
            buf.clear();
        }

        f2.close();
        f.close();

        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }
}
有帮助吗?

解决方案

我的经验与较大文件的尺寸了 java.nio 是的速度比 java.io. 扎扎实实地更快。 像>250%的范围。这就是说,我是消除明显的瓶颈,其中我建议你的微观基准可能会受到影响。潜在的区域调查:

缓冲区的大小。 算法你基本上是

  • 复制盘来缓冲
  • 复制缓冲区的磁盘

我自己的经验是,这个缓冲区的大小 成熟 调整。我已经决定4KB一部分,我的应用程序,256KB另一个。我怀疑你的代码是遭受如此大的缓冲区。运行一些基准与缓冲区的1KB,2KB、4KB、8KB,16KB,32KB和64KB,以证明它自己。

不执行java基准,即阅读和写信给同一磁盘。

如果你这样做,那么你真的是制定基准的磁盘,并不Java。我还将建议如果你的CPU是不忙的,那么可能是遇到一些其他的瓶颈。

不要使用一种缓冲,如果你不需要。

为什么复制记忆,如果你的目标是另一个磁盘或NIC?与较大文件的延迟incured是非微不足道的。

像其他所说,使用 FileChannel.transferTo()FileChannel.transferFrom().关键的优点是,JVM使用的操作系统的访问DMA(直接内存存取),如果存在的话。 (这是执行依赖性,但是,现代的太阳和IBM上版本的通用Cpu是好去。) 会发生什么情况是数据直接从光盘,旅,然后到目的地...绕过任何电路,通过RAM或CPU。

该网络应用程序的我花了我的白天和晚上的工作是非常IO重。我已经做了微基准和现实世界的基准。结果是在我的博客,看看-看到:

使用生产的数据和环境

微型基准是易于出现失真。如果可以的话,作出努力,收集的数据正是你打算做什么,你指望,你的硬件期望。

我的基准是固和可靠的,因为他们采取了地方上的生产系统,一个强壮的系统,系统的载荷下,聚集在日志。 我的笔记本电脑的7200转2.5"SATA驱动,同时我看着强烈的JVM工作,我的硬盘。

你怎么运行了?它的事项。

其他提示

如果你要比较的东西是文件复制的性能,那么对于频道测试,你应该这样做:

final FileInputStream inputStream = new FileInputStream(src);
final FileOutputStream outputStream = new FileOutputStream(dest);
final FileChannel inChannel = inputStream.getChannel();
final FileChannel outChannel = outputStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
inputStream.close();
outputStream.close();

这不会比从一个通道缓冲到另一个通道慢,并且可能会大大加快。根据Javadocs:

  

许多操作系统可以直接从文件系统缓存向目标通道传输字节,而无需实际复制它们。

根据我的测试(windows7资64位,6GB RAM、Java6),仁王transferFrom是快速的,只有小型的文件和变得非常缓慢,在更大的文件。仁王databuffer触始终超过标准IO.

  • 复制1000x2MB

    1. 仁王(transferFrom)~2300ms
    2. 仁王(直接datababuffer5000b翻)~3500ms
    3. 标准IO(缓冲区5000b)~6000ms
  • 复制100x20mb

    1. 仁王(直接datababuffer5000b翻)~4000ms
    2. 仁王(transferFrom)~5000
    3. 标准IO(缓冲区5000b)~6500ms
  • 复制1x1000mb

    1. 仁王(直接datababuffer5000b翻)~4500s
    2. 标准IO(缓冲区5000b)~7000ms
    3. 仁王(transferFrom)~8000ms

的传输到()方法工作上的大块的文件;是不是打算作为一个高级文件复制的方法:如何复制的一个大型文件,在Windows XP?

回答"有效性"的一部分问题:

一个相当微妙的陷阱的使用 FileChannelFileOutputStream 是执行任何其阻止操作(例如 read()write())从一个线程, 中断状态 将导致通道附近突然有 java.nio.channels.ClosedByInterruptException.

现在,这可能是一件好事,如果不论什么 FileChannel 用于一部分的线的主要功能,并设计了这一点考虑进去。

但它也可能是讨厌如果使用的一些辅助要素诸如有日志的功能。例如,可以找到你的记录输出突然关闭,如果日志的功能发生的被称为一线,也中断。

这是不幸的,这是很微妙,因为不计为这可能导致错误影响写的完整性。[1][2]

我测试了FileInputStream与FileChannel的性能,用于解码base64编码文件。在我的经验中,我测试了相当大的文件,传统的io总是比nio快一点。

由于几个io相关类中的同步化开销,FileChannel可能在jvm的早期版本中具有优势,但是现代jvm非常适合删除不需要的锁。

如果您没有使用transferTo功能或非阻塞功能,您将不会注意到传统IO和NIO之间的区别(2),因为传统的IO映射到NIO。

但是如果你可以使用像transferFrom / To这样的NIO功能或者想要使用Buffers,那么NIO当然是可行的。

我的经验是,对于小文件,NIO要快得多。但是当谈到大文件时,FileInputStream / FileOutputStream要快得多。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top