java文件拷贝时 buff给多大合适_学习 Java 基础知识, 打通面试关十一~ 文件的拷贝...

学习 Java 基础知识, 打通面试关十一~ 文件的拷贝

上一篇文章我们说了 IO 流操作, 里面区分了 BIO,NIO,AIO, 这些方式提高了我们在文件的操作, 那么我们使用文件拷贝的时候, IO 里面又提供了什么内容呢? 在 JDK1.7 以前是没有文件的拷贝的方式的.

四种方式 IO 流的拷贝操作

使用 FileStreams

我们使用的是 JDK 中最直接的方式读取文件, 然后写入到文件中. 从步骤上来说分为两步, 读取, 然后写入, 追一个十分低效率的方式. 增加了系统上下文切换的的次数./**

* 拷贝文件

* @param source 源文件

* @param dest 目的文件

* @throws Exception

*/

publicvoidcopyFile(Filesource,Filedest)throwsException{

try(InputStreamis=newFileInputStream(source);

OutputStreamout=newFileOutputStream(dest);){

byte[]buff=newbyte[2048];

intlength;

while((length=is.read(buff))>0){

out.write(buff,0,length);

}

}catch(Exceptione){

e.printStackTrace();

}

}

使用 FileChannel 复制

我们在上篇文章学习 Java 基础知识, 打通面试关十~ IO 流中说到

文件读取使用 NIO 解决堵塞的问题, 在这里使用 NIO 的方式也能提高文件的复制功能. 我们使用的 NIO 中的 transferFrom 方法. 该方式更能利用现代的操作系统的底层机制, 避免了一些拷贝和上下文的切换./**

* Nio 的方式 来拷贝文件

* @param source 源文件

* @param dest 目的文件

* @throws Exception

*/

publicvoidcopyFileNio(Filesource,Filedest)throwsException{

try(FileChannelin=newFileInputStream(source).getChannel();

FileChannelout=newFileOutputStream(dest).getChannel();){

out.transferTo(in,0,in.size());

// 或者采用下面这种方式 使用循环的方式把数据写过去

longcount=in.size();

while(count>0){

longlength=in.transferTo(in.position(),count,out);

in.position(count-=length);

}

}catch(Exceptione){

e.printStackTrace();

}

}

使用 Apache 工具包 Commons IO 复制/**

* 使用 Common IO 操作

* @param source 源文件

* @param dest 目的文件

* @throws Exception

*/

publicvoidcopyFileNCom(Filesource,Filedest)throwsException{

try{

FileUtils.copyFile(source,dest);

}catch(Exceptione){

e.printStackTrace();

}

}

Java7 上增加的 copy 方式privatestaticvoidcopyFiles(Filesource,Filedest)

throwsIOException{

Files.copy(source.toPath(),dest.toPath());

}

在这里我们深入了解其拷贝基础 进入源码查看实现有多种的 copy 方式, 方法提供了三个 , 在这里已经不限制文件, 可以是其他的流等. 虽然最终的拷贝里面内部用的不是我们想说的 transferTo, 但是内部是通过本地技术来实现用户生态拷贝. 减少了一部分的上下文切换, 提高了效率问题

ab7653affab982b574eb7acc55df2e04.gif

copy 的几种方式

这几种方式的区别

在 Copy 的方式上不管是 Java7 还是 io 中的读取文件写入文件, Apache 中的工具包 这样的方式文件上下行切换比较多. 我们来学习下底层切换的知识.

用户态与内核态

用户态, 当进程执行用户自己的代码时, 这种状态称为用户态.

内核态, 当程序执行系统调用的时候进入内核代码执行, 我们把其称为内核运行状态.

用户栈, 指向的是用户地址空间.

内核栈, 指向的是内核空间地址

他们之间的关系可以参考这张图

ab7653affab982b574eb7acc55df2e04.gif

关系图

ab7653affab982b574eb7acc55df2e04.gif

进程通信

通过这两种方式的话增加了额外的开销, 会降低系统 IO 的能力.

而在 NIO 的方式中, 改变了实现的方式, 采用了零拷贝的技术, 数据传输, 不需要到用户态的参与, 直接在内核上实现. 这种减少了内核态与用户态之间的交流沟通, 进而提高了应用的拷贝心梗. 并且 TransferTo 不仅可以用在文件拷贝上, 还以用在读取文件进行 Socket 发送等方式.

ab7653affab982b574eb7acc55df2e04.gif

调用 TransferToSocketChannelsocket=SocketChannel.open();

try(FileChannelin=newFileInputStream(source).getChannel();

FileChannelout=newFileOutputStream(dest).getChannel();){

out.transferFrom(in,0,in.size());

// 或者采用下面这种方式 使用循环的方式把数据写过去

longcount=in.size();

while(count>0){

// 在这里采用读取数据文件直接发送给 Socket 打开的 socket 链接

longlength=in.transferTo(in.position(),count,socket);

in.position(count-=length);

}

}catch(Exceptione){

e.printStackTrace();

}

总而言之在系统文件拷贝情况下

我们应该注意减少系统的上下文切换, 多余的 IO 操作等, 减少 IO 次数等,

减少不必要的操作例如编码解码, 序列化, 等信息在网络之间传输最好使用二进制信息传输.

来源: http://www.jianshu.com/p/a125d965a831

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值