java中io与nio复制文件性能对比
1. 在JAVA传统的IO系统中,读取磁盘文件数据的过程如下:
以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区。参看read(byte b[])方法的源码,可知,它会在内部再调用readBytes(b, 0, b.length)方法,而且readBytes(b, 0, b.length)方法是一个native方法(即本地方法),最终通过这个本地方法来发起一次系统调用,即调用系统内核的read()方法,内核从磁盘读取数据到内核缓冲区,这个过程由磁盘控制器通过DMA操作将数据从磁盘读取内核缓冲区,此过程不依赖于CPU。然后用户进程再将数据从内核缓冲区拷贝到用户空间缓冲区。用户进程再从用户空间缓冲区中读取数据。因为用户进程是不可以直接访问硬件的。所以需要通过内核来充当中间人的作用来实现文件的读取。
整个过程如下图所示:
2. 自从JAVA 1.4以后,JAVA在NIO在引入了文件通道的概念,和传统IO最大的区别是:传统IO是基于Byte(字节)和Stream(流)的,而NIO是基于Buffer(缓冲)、Channel(通道)在API中有提供了一个FileChannel类和Selector(选择器)的,该类与传统的IO流进行关联。可以由FileInputStream或FileOutputStream获取该文件通道,我们可以通过通道对文件进行读写操作。
3.JAVA NIO中还引入了文件内存映射的概念:现代操作系统大都支持虚拟内存映射,这样,我们可以把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就可以填充对内核与用户空间进程同时可见的缓冲区了。如下图所示
下面就看下使用IO,BufferedIO和NIO分别实现的文件复制耗时比较:11兆音频文件
传统IO方法实现文件拷贝耗时:21ms
利用NIO文件通道方法实现文件拷贝耗时:16ms
利用NIO文件内存映射及文件通道实现文件拷贝耗时:7ms
利用FileUtils文件拷贝工具类耗时:53ms
package com.maystar.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import org.apache.commons.io.FileUtils;
public class FileCopyTest {
public static void main(String[] args) throws Exception {
String sourcePath = "F:\\glzmv.mp3";
String destPath1 = "F:\\glzmvCopy1.mp3";
String destPath2 = "F:\\glzmvCopy2.mp3";
String destPath3 = "F:\\glzmvCopy3.mp3";
String destPath4 = "F:\\glzmvCopy4.mp3";
long t1 = System.currentTimeMillis();
traditionalCopy(sourcePath,destPath1);
long t2 = System.currentTimeMillis();
System.out.println("传统IO方法实现文件拷贝耗时:" + (t2-t1) + "ms");
nioCopy(sourcePath,destPath2);
long t3 = System.currentTimeMillis();
System.out.println("利用NIO文件通道方法实现文件拷贝耗时:" + (t3-t2) + "ms");
nioCopy2(sourcePath,destPath3);
long t4 = System.currentTimeMillis();
System.out.println("利用NIO文件内存映射及文件通道实现文件拷贝耗时:" + (t4-t3) + "ms");
nioCopy3(sourcePath,destPath4);
long t5 = System.currentTimeMillis();
System.out.println("利用FileUtils文件拷贝耗时:" + (t5-t4) + "ms");
}
private static void nioCopy3(String sourcePath, String destPath) throws Exception {
File source = new File(sourcePath);
File dest = new File(destPath);
FileUtils.copyFile(source, dest);//查看源码commons-io-2.4也使用的是nio操作,实现类似nioCopy操作,但是为什么效率比nioCopy要低,原因是在FileUtils.copyFile执行doCopyFile完成调用IOUtils工具类关闭流操作,根据不同类型的流调用对应的构造方法。
}
private static void nioCopy2(String sourcePath, String destPath) throws Exception {
File source = new File(sourcePath);
File dest = new File(destPath);
if(!dest.exists()) {
dest.createNewFile();
}
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(dest);
FileChannel sourceCh = fis.getChannel();
FileChannel destCh = fos.getChannel();
MappedByteBuffer mbb = sourceCh.map(FileChannel.MapMode.READ_ONLY, 0, sourceCh.size());
destCh.write(mbb);
sourceCh.close();
destCh.close();
}
private static void traditionalCopy(String sourcePath, String destPath) throws Exception{
File source = new File(sourcePath);
File dest = new File(destPath);
if(!dest.exists()) {
dest.createNewFile();
}
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(dest);
byte [] buf = new byte [fis.available()];
int len = 0;
while((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fis.close();
fos.close();
}
private static void nioCopy(String sourcePath, String destPath) throws Exception{
File source = new File(sourcePath);
File dest = new File(destPath);
if(!dest.exists()) {
dest.createNewFile();
}
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(dest);
FileChannel sourceCh = fis.getChannel();
FileChannel destCh = fos.getChannel();
destCh.transferFrom(sourceCh, 0, sourceCh.size());
sourceCh.close();
destCh.close();
}
}

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Guide de la racine carrée en Java. Nous discutons ici du fonctionnement de Square Root en Java avec un exemple et son implémentation de code respectivement.

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du numéro Armstrong en Java. Nous discutons ici d'une introduction au numéro d'Armstrong en Java ainsi que d'une partie du code.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est
