java nio效率_Java IO和Java NIO在文件拷贝上的性能差异分析

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

1a5a921d47d6b0cbb0074cb0d1db4fb0.png

2.  自从JAVA 1.4以后,JAVA在NIO在引入了文件通道的概念,在API中有提供了一个FileChannel类。该类与传统的IO流进行关联。可以由FileInputStream或FileOutputStream获取该文件通道,我们可以通过通道对文件进行读写操作。

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

cf99f40375da98f78dbe0783e6e99189.png

这样做的好处是,我们在读取磁盘文件时,再也不用通过内核缓冲区到用户进程缓冲区的来回拷贝操作了。操作系统会通过一些页面调度算法来将磁盘文件载入对分页区进行高速缓存的物理内存。我们就可以通过映射后物理内存来读取磁盘文件了。

4.  下面我们通过三种不同方式文件拷贝的案例来验证文件通道及文件内存映射在IO系统中的作用。测试环境为windows 32位系统和JDK1.6。代码中使用的测试文件movie.avi为一个123MB的视频文件。代码如下:

1 packagecn.com.hbust.nio.file;2

3 importjava.io.File;4

5 importjava.io.FileInputStream;6

7 importjava.io.FileOutputStream;8

9 importjava.nio.MappedByteBuffer;10

11 importjava.nio.channels.FileChannel;12

13

14

15 public classFileCopyTest {16

17

18

19 public static void main(String[] args) throwsException {20

21 String sourcePath = "F:\\mywork\\javademo\\dir1\\movie.avi";22

23 String destPath1 = "F:\\mywork\\javademo\\dir2\\movie1.avi";24

25 String destPath2 = "F:\\mywork\\javademo\\dir2\\movie2.avi";26

27 String destPath3 = "F:\\mywork\\javademo\\dir2\\movie3.avi";28

29 long t1 =System.currentTimeMillis();30

31 traditionalCopy(sourcePath,destPath1);32

33 long t2 =System.currentTimeMillis();34

35 System.out.println("传统IO方法实现文件拷贝耗时:" + (t2-t1) + "ms");36

37

38

39 nioCopy(sourcePath,destPath2);40

41 long t3 =System.currentTimeMillis();42

43 System.out.println("利用NIO文件通道方法实现文件拷贝耗时:" + (t3-t2) + "ms");44

45

46

47 nioCopy2(sourcePath,destPath3);48

49 long t4 =System.currentTimeMillis();50

51 System.out.println("利用NIO文件内存映射及文件通道实现文件拷贝耗时:" + (t4-t3) + "ms");52

53

54

55 }56

57

58

59 private static void nioCopy2(String sourcePath, String destPath) throwsException {60

61 File source = newFile(sourcePath);62

63 File dest = newFile(destPath);64

65 if(!dest.exists()) {66

67 dest.createNewFile();68

69 }70

71 FileInputStream fis = newFileInputStream(source);72

73 FileOutputStream fos = newFileOutputStream(dest);74

75 FileChannel sourceCh =fis.getChannel();76

77 FileChannel destCh =fos.getChannel();78

79 MappedByteBuffer mbb = sourceCh.map(FileChannel.MapMode.READ_ONLY, 0, sourceCh.size());80

81 destCh.write(mbb);82

83 sourceCh.close();84

85 destCh.close();86

87 }88

89

90

91

92

93 private static void traditionalCopy(String sourcePath, String destPath) throwsException{94

95 File source = newFile(sourcePath);96

97 File dest = newFile(destPath);98

99 if(!dest.exists()) {100

101 dest.createNewFile();102

103 }104

105 FileInputStream fis = newFileInputStream(source);106

107 FileOutputStream fos = newFileOutputStream(dest);108

109 byte [] buf = newbyte [512];110

111 int len = 0;112

113 while((len = fis.read(buf)) != -1) {114

115 fos.write(buf, 0, len);116

117 }118

119 fis.close();120

121 fos.close();122

123 }124

125

126

127 private static void nioCopy(String sourcePath, String destPath) throwsException{128

129 File source = newFile(sourcePath);130

131 File dest = newFile(destPath);132

133 if(!dest.exists()) {134

135 dest.createNewFile();136

137 }138

139 FileInputStream fis = newFileInputStream(source);140

141 FileOutputStream fos = newFileOutputStream(dest);142

143 FileChannel sourceCh =fis.getChannel();144

145 FileChannel destCh =fos.getChannel();146

147 destCh.transferFrom(sourceCh, 0, sourceCh.size());148

149 sourceCh.close();150

151 destCh.close();152

153 }154

155 }

每执行完一次拷贝之后,将F:\mywork\javademo\dir2\目录中的内容删除掉,重复执行8次。观察测试结果如下:时间单位为ms(毫秒)

c89240c5c414566b01066de5a1e98a0c.png

由上表可知,传统IO方式平均拷贝完成时间约为1968ms,NIO文件通道方式平均拷贝完成时间约为1672ms,文件内存映射及文件通道方式平均拷贝完成时间约为1418ms。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值