话题:假设机器只有500M内存,有一个1.23GB的文件,要从一个目录复制到另外一个目录
目的:比较IO与NIO的读取速度效率
细节:大文件不能一次读到内存中,否则会内存溢出,只能每次读取固定大小的数据流
下面进行代码实现,在实现代码中,有的代码是一次性读取全部内容到内存中,有的是读取固定大小,分别看看这些方法读取文件速度的差异
文件大小 1.23GB
1.使用RandomAccessFile读取文件,FileOutputStream写文件,耗时:8768ms
2.使用BufferedInputStream读取文件,BufferedOutputStream写文件,耗时:2202ms
3.使用Scanner读文件,FileOutputStream写文件,耗时:120945ms
4.使用NIO,FileChannel读写文件,耗时:
- NIO每次读取1M,耗时:8947ms
- NIO每次读取5M,耗时:2976ms
- NIO每次读取10M,耗时:1802ms
- NIO每次读取20M,耗时:1279ms
基本上使用NIO和有缓冲区的IO–BufferedInputStream读写文件速度最快,通过任务管理器观察对内存的使用基本在100M上下浮动
package com.zypcy.readbigfile;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;
/**
* 读取大文件
* 分别测试不同文件流IO与NIO读取的效率
* 因文件很大,机器可用内存较小,无法一次读取全部内容,需要读取固定大小的数据
* @author zhuyu
*/
public class Demo {
public static void main(String[] args) {
String filePath = "D:\\project\\java\\workspace\\DemoThread\\src\\com\\zypcy\\readbigfile\\bigdata.zip";
String newPath = "D:\\project\\java\\workspace\\DemoThread\\src\\com\\zypcy\\readbigfile\\output.zip";
try {
File file = new File(filePath);
if(!file.exists()){
return;
}
File newFile = new File(newPath);
//randomAccessRead(file ,newFile);
//测试:读取1.23GB文件耗时:8768ms
//bufferedRead(file ,newFile);
//测试:读取1.23GB文件耗时:2202ms
//scannerRead(file ,newFile);
//测试:读取1.23GB文件耗时:120945ms
fileChannelRead(file ,newFile);
//每次读取1M,耗时:8947ms
//每次读取5M,耗时:2976ms
//每次读取10M,耗时:1802ms
//每次读取20M,耗时:1279ms
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用 RandomAccessFile 读取文件
* @param file
* @param newFile
*/
public static void randomAccessRead(File file , File newFile){
//测试:读取1.23GB文件耗时:8768ms
long d1 = System.currentTimeMillis();
RandomAccessFile raf = null;
OutputStream output = null;
try {
raf = new RandomAccessFile(file , "rw");
output = new FileOutputStream(newFile);
int len = 0; //每次读取内容长度
byte[] data = new byte[1024];//内容缓冲区
while((len = raf.read(data)) != -1){
output.write(data, 0, len);
}
long d2 = System.currentTimeMillis();
System.out.println("randomAccessRead读取完成,耗时:" + (d2 - d1));
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(raf != null){
raf.close();
}
if(output != null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 使用NIO的FileChannel读取
* @param file
* @param newFile
*/
public static void fileChannelRead(File file , File newFile){
//1.23GB文件
//每次读取1M,耗时:8947ms
//每次读取5M,耗时:2976ms
//每次读取10M,耗时:1802ms
//每次读取20M,耗时:1279ms
long d1 = System.currentTimeMillis();
FileInputStream in = null;
FileOutputStream output = null;
FileChannel fic = null;
FileChannel foc = null;
try {
in = new FileInputStream(file);
output = new FileOutputStream(newFile);
fic = in.getChannel();
foc = output.getChannel();
//fic.transferTo(0, fic.size(), foc);
ByteBuffer buf = ByteBuffer.allocate(20480);
while(fic.read(buf) != -1){
buf.flip();//切换到读取数据模式
foc.write(buf);//将缓冲区的数据写入通道中
buf.clear();//清空缓冲区
}
long d2 = System.currentTimeMillis();
System.out.println("fileChannelRead读取完成,耗时:" + (d2 - d1));
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(in != null){
in.close();
}
if(output != null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 使用IO的缓冲区读取
* @param file
* @param newFile
*/
public static void bufferedRead(File file , File newFile){
//测试:读取1.23GB文件耗时:2202
long d1 = System.currentTimeMillis();
InputStream in = null;
OutputStream output = null;
try {
in = new BufferedInputStream(new FileInputStream(file)) ;
output = new BufferedOutputStream(new FileOutputStream(newFile));
int len = 0;
byte[] data = new byte[1024];
while((len = in.read(data)) != -1){
output.write(data, 0, len);
}
long d2 = System.currentTimeMillis();
System.out.println("bufferedRead读取完成,耗时:" + (d2 - d1));
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(in != null){
in.close();
}
if(output != null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 使用Scanner一行一行读取
* @param file
* @param newFile
*/
public static void scannerRead(File file , File newFile){
//读取1.23GB文件耗时:120945
long d1 = System.currentTimeMillis();
InputStream in = null;
OutputStream output = null;
try {
in = new FileInputStream(file);
output = new FileOutputStream(newFile);
Scanner sc = new Scanner(in, "UTF-8");
//sc.useDelimiter("\\r\\n");
while(sc.hasNext()){
String content = sc.nextLine();
output.write(content.getBytes("UTF-8"));
}
long d2 = System.currentTimeMillis();
System.out.println("scannerRead读取完成,耗时:" + (d2 - d1));
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(in != null){
in.close();
}
if(output != null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}