Java仁王FileChannel与FileOutputstream性/有效性
-
05-07-2019 - |
题
我试图找出如果有任何差别性能(或者优点),当我们使用仁王 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
- 仁王(transferFrom)~2300ms
- 仁王(直接datababuffer5000b翻)~3500ms
- 标准IO(缓冲区5000b)~6000ms
复制100x20mb
- 仁王(直接datababuffer5000b翻)~4000ms
- 仁王(transferFrom)~5000
- 标准IO(缓冲区5000b)~6500ms
复制1x1000mb
- 仁王(直接datababuffer5000b翻)~4500s
- 标准IO(缓冲区5000b)~7000ms
- 仁王(transferFrom)~8000ms
的传输到()方法工作上的大块的文件;是不是打算作为一个高级文件复制的方法:如何复制的一个大型文件,在Windows XP?
回答"有效性"的一部分问题:
一个相当微妙的陷阱的使用 FileChannel
在 FileOutputStream
是执行任何其阻止操作(例如 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要快得多。