IO流不同方法copy文件的效率分析

IO流copy文件的几种方法介绍

1、FileInputStream和FileOutputStream:文件的读写一般是以字节为单位的,前者从文件中获取字节数据,后者将字节数据写入文件。这种方式获取的对象对于数据的读写是逐字节的,稍后我们将测试其读写的速度。在读写的过程中我们可以这样理解,read()方法查看其底层可以发现是一个native方法,native方法连接了java和底层的C语言,IO流读取到了数据,保存在一个8位(一个字节)的寄存器中,最简单的文件流就是对这个寄存器上的数据进行操作的,这也是为什么这种方法是逐字节读写的原因,这种方式在每次读完一个字节的的时候,就会产生溢出中断,CPU再去响应中断请求,这样一来,其效率是很低下的,在读大文件的时候,这种方法就捉襟见肘了。
2、BufferedInputStream和BufferedOutputStream:缓冲输入流和缓冲输出流,怎么获得缓冲流对象呢?我们通过把方法1中的对象用缓冲流的构造方法包装即可获得。那么什么是缓冲呢?JVM内存中为它开辟了一块区域,用来临时存放数据,相当于是在方法1中加了一块区域,读到的字节都会经过这个中间环节,先写到缓冲区,当缓冲区读满或者给其相应强制清除缓冲的指令(flush方法)时,就会一次性读取缓冲区的所有数据。它的优越之处显而易见,CPU可以有更多的时间去处理别的事务了,一次性地读取大大提升了读取的速度,程序在性能上明显优于方法1,我们在之后的测试中也可以看到。
3、自定义byte[] buf字节数组创建缓冲区:和方法2的原理类似,但这种方法使得我们对数据的处理更加有可操作性,我们可以自己定义缓冲区的大小,因为这个空间是我们自己定义的。在流程上,我们先把数据写入数组,获取长度,再把字节数组的数据写到文件中,这依然是一种批量操作。

测试三种方法copy文件的速度(java程序)

1、代码实现:我这里分别写了三个方法,测试程序传文件所花费的时间,第三种方法修改入口参数,可以自定义缓冲区字节数组的长度。

public class Test {
	 public static void main(String[] args){
		 Test test = new Test();
		 test.withoutBuffer();//测试不加缓冲
		 test.addBuffer(); //测试加缓冲
		 test.BufferByte(1024);//自定义缓冲数组长度		 
	 }
	/**
	 * 不加缓冲的文件传输测试
	 */
	public void withoutBuffer(){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\云计算必读-Google_三大论文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get\\云计算必读-Google_三大论文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file); //获取文件输入流
		FileOutputStream fos = new FileOutputStream(file1); //获取文件输出流
		int value=0;
	        long startTime = System.currentTimeMillis(); //执行前的时间
		while((value = fis.read())!=-1){   //读取下一个字节,返回值是字节对应的字节对应的字节值,读到-1则表示没有数据了
			fos.write(value);	//把这个字节写出去		
		}
		long endTime = System.currentTimeMillis(); //执行后的时间
		long time = endTime-startTime; //花费时间
		System.out.println("不加缓冲copy文件用了:"+time+"ms");
		fos.close();  //关资源
		fis.close();		
		}catch(IOException e){
			e.printStackTrace();
		}			
	}
	/**
	 * 添加缓冲的文件传输测试
	 */
	public void addBuffer(){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\云计算必读-Google_三大论文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get1\\云计算必读-Google_三大论文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file);
		BufferedInputStream bis = new BufferedInputStream(fis); //把文件输入流包装为缓冲流
		FileOutputStream fos = new FileOutputStream(file1);
		BufferedOutputStream bos = new BufferedOutputStream(fos); //把文件输出流包装为缓冲流
		int length=0;
	        long startTime = System.currentTimeMillis();
		while((length = bis.read())!=-1){
			bos.write(length);			
		}
		long endTime = System.currentTimeMillis();
		long time = endTime-startTime;	
		System.out.println("加缓冲后的文件传输时间:"+time+"ms");
		bos.flush();
		bos.close();
		fos.close();
		bis.close();
		fis.close();					
		}catch(IOException e){
			e.printStackTrace();
		}				
	}
	/**
	 * 使用自定义的字节数组作为缓冲区
	 */
	public void BufferByte(int len){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\云计算必读-Google_三大论文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get2\\云计算必读-Google_三大论文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file); //获取文件输入流
		FileOutputStream fos = new FileOutputStream(file1); //获取文件输出流
		int length=0; //记录每次读取到的字节长度
		byte[] buf = new byte[len];  //根据输入值自定义缓冲区长度
	        long startTime = System.currentTimeMillis(); //执行前的时间
		while((length = fis.read(buf))!=-1){   //读取字节到字节数组中,最多一次读1024个
			fos.write(buf,0,length);	//把这些数据写到文件
			if(length<len)  //最后的数据读完后退出,防止阻塞
				break;
		}
		long endTime = System.currentTimeMillis(); //执行后的时间
		long time = endTime-startTime; //花费时间
		System.out.println("自定义缓冲字节数组长度为"+len+"字节时,copy文件用了:"+time+"ms");
		fos.close();  //关资源
		fis.close();		
		}catch(IOException e){
			e.printStackTrace();
		}			
	}	
}

2、运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、结果分析:观察数据,我们可以发现,不加缓冲逐字节读取花费的时间是很长的,在程序运行的时候我们就可以明显发现这一点。在加了java自带的缓冲区后,文件的传输速度明显提升,只需要几十毫秒。copy速度最快的是第三种方法,我们自定义的缓冲区在1024字节大小时,其速度略微慢于方法2,但当我们把缓冲区增加后,其速度就比方法2快了,且其内存区域越大,copy速度越快。因此,我们可以得出结论,最优的方案是自定义缓冲区,其次是采用java自带缓冲区吗,逐字节读取的方法我们应该尽量避免使用,效率低下。当程序反复读写的次数越少,其copy速度就会越快。查阅资料可以知道java自带的缓冲区默认是8192字节,在第二个测试案例中我们可以发现,自定义相同大小的区域,方法3是比方法2要快的,因此,效率最高的方法依然是自定义字节数组作为缓冲区。

猜你喜欢

转载自blog.csdn.net/mayifan_blog/article/details/84954609
今日推荐