Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。

FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。

对于文件的复制,平时我们都是使用输入输出流进行操作,利用源文件创建出一个输入流,然后利用目标文件创建出一个输出流,最后将输入流的数据读取写入到输出流中。这样也是可以进行操作的。但是利用fileChannel是很有用的一个方式。它能直接连接输入输出流的文件通道,将数据直接写入到目标文件中去。而且效率更高。
FileChannel是一个用读写,映射和操作一个文件的通道。除了读写操作之外,还有裁剪特定大小文件truncate(),强制在内存中的数据刷新到硬盘中去force(),对通道上锁lock()等功能。

他们的使用分别如下面代码:

ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//读取1024字节内容到byteBuffer钟
fileChannelInput.read(byteBuffer);

解释:上面代码首先创建一个1024大小的缓冲对象,然后在输入通道中读取1024大小数据,放入到缓冲对象中。

byteBuffer.clear();
byteBuffer.put("需要写入的数据".getBytes());
//类似于flush()函数功能,将buffer里面的数据刷新出去
byteBuffer.flip();
//检查是否还有数据未写入
while (byteBuffer.hasRemaining())
fileChannelOutput.write(byteBuffer);

解释:上面的代码是将一段字符串写入到输出文件通道中,因为写入的时候并不保证能一次性写入到文件中,所以需要进行判断是否全部写入,如果没有需要再次调用写入函数操作

//获取文件通道位置
fileChannelInput.position();
fileChannelInput.size();
//截取内容
fileChannelInput.truncate(1024);
//强制刷新数据到硬盘
fileChannelInput.force(true);

解释:上面的代码是获取文件通道的位置和大小。truncate()方法是截取1024大小的数据,指定长度后面的部分将被删除。以及将数据强制刷新到硬盘中,因为系统会将数据先保存在内存中,不保证数据会立即写入到硬盘中,所以有这个需求,就可以直接强制数据写入内存中。

使用

说那么多可能没用,我们还是直接来看看分别使用两种方法进行文件复制的对比。

首先是普通的输入输出流进行复制文件:

import org.springframework.util.ResourceUtils;

import java.io.*;

/**
* 普通的文件复制
*/
public class FileCopyForNomal {
public void fileCopy(File fromFile,File toFile){
InputStream inputStream = null;
OutputStream outputStream = null; try {
inputStream = new BufferedInputStream(new FileInputStream(fromFile));
outputStream = new BufferedOutputStream(new FileOutputStream(toFile,true));//追加
byte [] bytes = new byte[1024];
int i;
while((i=inputStream.read(bytes)) != -1){
outputStream.write(bytes,0,i);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(inputStream!=null){
inputStream.close();
}if(outputStream!=null){
outputStream.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
} public static void main(String[] args) throws FileNotFoundException {
String from = ResourceUtils.getFile("classpath:a.txt").getPath();//这边文件是在target下
System.out.println(from);
String to = ResourceUtils.getFile("classpath:b.txt").getPath();//这边文件是在target下
System.out.println(to);
File fromFile = new File(from);
File toFile = new File(to); Long startTime = System.currentTimeMillis();
new FileCopyForNomal().fileCopy(fromFile,toFile);
Long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
}

结果:

G:\idea_workspace\io\filechannel\target\classes\a.txt
G:\idea_workspace\io\filechannel\target\classes\b.txt
48

下面再看一下利用fileChannel进行文件的复制操作。

import org.springframework.util.ResourceUtils;

import java.io.*;
import java.nio.channels.FileChannel; /**
* 通道文件复制
*/
public class FileCopyForChannel {
public void fileCopy(File fromFile, File toFile){
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
FileChannel fileChannelInput = null;
FileChannel fileChannelOutput = null;
try {
fileInputStream = new FileInputStream(fromFile);
fileOutputStream = new FileOutputStream(toFile);
//得到fileInputStream的文件通道
fileChannelInput = fileInputStream.getChannel();
//得到fileOutputStream的文件通道
fileChannelOutput = fileOutputStream.getChannel();
//将fileChannelInput通道的数据,写入到fileOutputStream中
fileChannelInput.transferTo(0,fileChannelInput.size(),fileChannelOutput);
}catch(IOException e){
e.printStackTrace();
}finally {
try {
if (fileInputStream != null)
fileInputStream.close();
if (fileChannelInput != null)
fileChannelInput.close();
if (fileOutputStream != null)
fileOutputStream.close();
if (fileChannelOutput != null)
fileChannelOutput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) throws FileNotFoundException {
String from = ResourceUtils.getFile("classpath:a.txt").getPath();//这边文件是在target下
System.out.println(from);
String to = ResourceUtils.getFile("classpath:b.txt").getPath();//这边文件是在target下
System.out.println(to);
File fromFile = new File(from);
File toFile = new File(to); Long startTime = System.currentTimeMillis();
new FileCopyForChannel().fileCopy(fromFile,toFile);
Long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
}
}

结果:

G:\idea_workspace\io\filechannel\target\classes\a.txt
G:\idea_workspace\io\filechannel\target\classes\b.txt
22

运行代码之后,复制一个文件,对比两种复制方法,发现利用filechannel使用的时间比普通的读取输入时间缩短了将近一半。尤其是在进行大文件复制的时候,filechannel显得更加有优势。

总结

这里我们了解了FileChannel类,知道了它所具有的特点和功能,那么我们就可以好好的使用它了。尤其是在我们复制文件的时候,可以更好的利用这个类,可以提高效率,也可以防止出现oom等其它情况。

源码地址:https://github.com/qjm201000/io_nio_filechannel.git

最新文章

  1. C Primer Plus_第5章_运算符、表达式和语句_编程练习
  2. CSS属性之float学习心得
  3. iOS中JSONModel的使用
  4. maven异常解决:编码GBK的不可映射字符
  5. CUBRID学习笔记 26 数据类型3cubrid教程
  6. ubuntu命令查补
  7. Session,Cookie 和local storage的区别
  8. JAVA GUI学习 - JSplitPane分屏组件学习
  9. TFboy养成记 多层感知器 MLP
  10. laravel 500错误的一个解决办法
  11. 游戏2048源代码 - C语言控制台界面版
  12. Java集合List、Set、Map
  13. 关于Android UI 优化
  14. JMeter采用NON GUI模式时如何记录并查看错误
  15. STL标准库-Move对容器效率的影响
  16. ssh反向连接内网主机
  17. 静态构造器(static constructor)
  18. Ansible9:条件语句
  19. C#中的Invoke和BeginInvoke
  20. python教程(二)·变量

热门文章

  1. Git撤销对远程仓库的push&commit提交
  2. 1407251735-hd-美素数.cpp
  3. iOS_9_scrollView分页
  4. strlen, wcslen, _mbslen, _mbslen_l, _mbstrlen, _mbstrlen_l, setlocale(LC_CTYPE, "Japanese_Japan")(MSDN的官方示例)
  5. windows管理员利器之用Log Parser Studio分析IIS日志(附逐浪CMS官方命令集)
  6. Win8 Metro(C#)数字图像处理--2.49Zhang二值图像细化算法
  7. 如何线程调用C++类成员函数
  8. 浅谈网络I/O多路复用模型 select & poll & epoll
  9. Delphi 7下IGDIPlus库的使用
  10. BITED数学建模七日谈之一:参加全国大学生数学建模比赛前你需要积累哪些