Maison Java javaDidacticiel java中io与nio复制文件性能对比

java中io与nio复制文件性能对比

Nov 23, 2016 am 09:45 AM
java

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。然后用户进程再将数据从内核缓冲区拷贝到用户空间缓冲区。用户进程再从用户空间缓冲区中读取数据。因为用户进程是不可以直接访问硬件的。所以需要通过内核来充当中间人的作用来实现文件的读取。

整个过程如下图所示:p36004370.jpg

2.  自从JAVA 1.4以后,JAVA在NIO在引入了文件通道的概念,和传统IO最大的区别是:传统IO是基于Byte(字节)和Stream(流)的,而NIO是基于Buffer(缓冲)、Channel(通道)在API中有提供了一个FileChannel类和Selector(选择器)的,该类与传统的IO流进行关联。可以由FileInputStream或FileOutputStream获取该文件通道,我们可以通过通道对文件进行读写操作。

3.JAVA NIO中还引入了文件内存映射的概念:现代操作系统大都支持虚拟内存映射,这样,我们可以把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就可以填充对内核与用户空间进程同时可见的缓冲区了。如下图所示

p36004370.jpg

下面就看下使用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(); 
    
     } 
    
 } 


Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Repo: Comment relancer ses coéquipiers
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

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

Racine carrée en Java Racine carrée en Java Aug 30, 2024 pm 04:26 PM

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.

Nombre parfait en Java Nombre parfait en Java Aug 30, 2024 pm 04:28 PM

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.

Générateur de nombres aléatoires en Java Générateur de nombres aléatoires en Java Aug 30, 2024 pm 04:27 PM

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.

Weka en Java Weka en Java Aug 30, 2024 pm 04:28 PM

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.

Numéro Armstrong en Java Numéro Armstrong en Java Aug 30, 2024 pm 04:26 PM

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.

Numéro de Smith en Java Numéro de Smith en Java Aug 30, 2024 pm 04:28 PM

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.

Questions d'entretien chez Java Spring Questions d'entretien chez Java Spring Aug 30, 2024 pm 04:29 PM

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.

Break or Return of Java 8 Stream Forach? Break or Return of Java 8 Stream Forach? Feb 07, 2025 pm 12:09 PM

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

See all articles