文件拷贝, 使用 BIO,NIO的对比,四种写法性能分析。

测试环境: jdk 1.7 +  2G内存

测试代码基本上复制了: http://blog.csdn.net/tabactivity/article/details/9317143


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

package test;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

public class FileCopyTest

{

    public FileCopyTest()

    {

        File[] files = new File("c:/images").listFiles();

        String destFolderPath = "g:/images";

        long t = System.currentTimeMillis();

        try

        {

            for (File sourceFile : files)

            {

                traditionalCopy(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());

            }

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

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

        //删除刚刚创建的

        for (File file : new File(destFolderPath).listFiles())

        {

            file.delete();

        }

        t = System.currentTimeMillis();

        try

        {

            for (File sourceFile : files)

            {

                copyBIO(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());

            }

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

        System.out.println("传统IO + 缓存 方法实现文件拷贝耗时:" + (System.currentTimeMillis() - t) + "ms");

        //删除刚刚创建的

        for (File file : new File(destFolderPath).listFiles())

        {

            file.delete();

        }

        t = System.currentTimeMillis();

        try

        {

            for (File sourceFile : files)

            {

                nioCopy(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());

            }

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

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

        //删除刚刚创建的

        for (File file : new File(destFolderPath).listFiles())

        {

            file.delete();

        }

        t = System.currentTimeMillis();

        try

        {

            for (File sourceFile : files)

            {

                nioCopy2(sourceFile.getPath(), destFolderPath + "/" + sourceFile.getName());

            }

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

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

        //删除刚刚创建的

        for (File file : new File(destFolderPath).listFiles())

        {

            file.delete();

        }

    }

    private static void traditionalCopy(String sourcePath, String destPath) throws Exception

    {

        File source = new File(sourcePath);

        File dest = new File(destPath);

        FileInputStream fis = new FileInputStream(source);

        FileOutputStream fos = new FileOutputStream(dest);

        

        byte[] buf = new byte[8192];

        int len = 0;

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

        {

            fos.write(buf, 0, len);

        }

        fis.close();

        fos.close();

    }

    private static void copyBIO(String sourcePath, String destPath) throws Exception

    {

        File source = new File(sourcePath);

        File dest = new File(destPath);

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));

        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));

        byte[] buf = new byte[8192];

        int len = 0;

        while ((len = bis.read(buf)) != -1)

        {

            bos.write(buf, 0, len);

        }

        bis.close();

        bos.close();

    }

    private static void nioCopy(String sourcePath, String destPath) throws Exception

    {

        File source = new File(sourcePath);

        File dest = new File(destPath);

        FileInputStream fis = new FileInputStream(source);

        FileOutputStream fos = new FileOutputStream(dest);

        FileChannel sourceCh = fis.getChannel();

        FileChannel destCh = fos.getChannel();

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

        sourceCh.close();

        destCh.close();

    }

    private static void nioCopy2(String sourcePath, String destPath) throws Exception

    {

        File source = new File(sourcePath);

        File dest = new File(destPath);

        FileInputStream fis = new FileInputStream(source);

        FileOutputStream fos = new FileOutputStream(dest);

        FileChannel sourceCh = fis.getChannel();

        FileChannel destCh = fos.getChannel();

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

        destCh.write(mbb);

        sourceCh.close();

        destCh.close();

    }

}

测试结果有些地方还是感到意外:

复制到同一块硬盘的其他分区, 总文件大小: 33M,其中一个文件:16M

-----------------------------------------------------------------------------

传统IO方法实现文件拷贝耗时:1156ms

传统IO + 缓存 方法实现文件拷贝耗时:1312ms

利用NIO文件通道方法实现文件拷贝耗时:1109ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

传统IO方法实现文件拷贝耗时:1157ms

传统IO + 缓存 方法实现文件拷贝耗时:1312ms

利用NIO文件通道方法实现文件拷贝耗时:1078ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

传统IO方法实现文件拷贝耗时:1203ms

传统IO + 缓存 方法实现文件拷贝耗时:1172ms

利用NIO文件通道方法实现文件拷贝耗时:1157ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:891ms

传统IO方法实现文件拷贝耗时:984ms

传统IO + 缓存 方法实现文件拷贝耗时:984ms

利用NIO文件通道方法实现文件拷贝耗时:1172ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:938ms

复制到另一个硬盘, 总文件大小: 33M,其中一个文件:16M

-----------------------------------------------------------------------------

传统IO方法实现文件拷贝耗时:1110ms

传统IO + 缓存 方法实现文件拷贝耗时:1343ms

利用NIO文件通道方法实现文件拷贝耗时:984ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:937ms

传统IO方法实现文件拷贝耗时:985ms

传统IO + 缓存 方法实现文件拷贝耗时:1516ms

利用NIO文件通道方法实现文件拷贝耗时:1203ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:890ms

传统IO方法实现文件拷贝耗时:875ms

传统IO + 缓存 方法实现文件拷贝耗时:1203ms

利用NIO文件通道方法实现文件拷贝耗时:1391ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:1031ms

传统IO方法实现文件拷贝耗时:938ms

传统IO + 缓存 方法实现文件拷贝耗时:1266ms

利用NIO文件通道方法实现文件拷贝耗时:1453ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:968ms

复制到另一个硬盘, 总文件大小: 81M,其中一个文件:66M

-----------------------------------------------------------------------------

传统IO方法实现文件拷贝耗时:4812ms

传统IO + 缓存 方法实现文件拷贝耗时:6250ms

利用NIO文件通道方法实现文件拷贝耗时:3375ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:3453ms

传统IO方法实现文件拷贝耗时:5328ms

传统IO + 缓存 方法实现文件拷贝耗时:6110ms

利用NIO文件通道方法实现文件拷贝耗时:3766ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:3641ms

复制到移动硬盘(用了3年), 总文件大小: 33M,其中一个文件:16M

-----------------------------------------------------------------------------

传统IO方法实现文件拷贝耗时:16532ms

传统IO + 缓存 方法实现文件拷贝耗时:15828ms

利用NIO文件通道方法实现文件拷贝耗时:34437ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:34797ms

传统IO方法实现文件拷贝耗时:20672ms

传统IO + 缓存 方法实现文件拷贝耗时:19547ms

利用NIO文件通道方法实现文件拷贝耗时:33844ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:33375ms

复制到移动硬盘(用了3年), 总文件大小: 15M,单个文件:150KB左右。

-----------------------------------------------------------------------------

传统IO方法实现文件拷贝耗时:172ms

传统IO + 缓存 方法实现文件拷贝耗时:157ms

利用NIO文件通道方法实现文件拷贝耗时:188ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:313ms

传统IO方法实现文件拷贝耗时:156ms

传统IO + 缓存 方法实现文件拷贝耗时:156ms

利用NIO文件通道方法实现文件拷贝耗时:188ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:344ms

传统IO方法实现文件拷贝耗时:203ms

传统IO + 缓存 方法实现文件拷贝耗时:218ms

利用NIO文件通道方法实现文件拷贝耗时:187ms

利用NIO文件内存映射及文件通道实现文件拷贝耗时:282ms

总结:

1. 根据上面的测试结果表明,如果拷贝的是小文件(单个文件几百KB),使用NIO并不会比IO快.

如果拷贝的单个文件达到几十M+,使用NIO速度会快的比较明显。

2. 测试时还发现 traditionalCopy()无论处理小文件还是大文件都不比copyBIO()慢。

traditionalCopy()就是使用最基本的 FileInputStream 和 FileOutStream。

copyBIO()使用的是BufferedInputStream 和 BufferedOutputStream。

关于这一点,可能是因为 “从1.5开始,Java对InputStream/OutputStream 进行了重新改写,用的就是NIO,因此,就算你不显示声明要用NIO,只要你的类继承了InputStream/OutputStream就已经在用NIO了”

参考资料: http://zhidao.baidu.com/question/109313742.html

3. 测试拷贝到移动硬盘上时,使用传统的IO比NIO速度还快,并且快很多。(这块移动硬盘用了3年,写入速度不怎么样)

这个原因我无法解释,有谁能告诉我?

2014-03-02

时间: 2024-10-12 21:35:59

文件拷贝, 使用 BIO,NIO的对比,四种写法性能分析。的相关文章

Android点击事件的四种写法

Android点击事件的四种写法 一.Android点击事件的四种写法 1.点击事件的第一种写法 .  写一个内部类.实现点击事件的接口 bt.setOnClickListener(new MyButtonListener()); 2.点击事件的第二种写法,匿名内部类 bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { callPhone(); } }); 3.点击事件的第三种

Android中按钮的点击事件的四种写法

如题,在Android中按钮的点击事件有四种写法,如下图. 界面为四个Button+一个TextView+一个ImageView activity_main布局文件如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="

数字集成电路设计-12-状态机的四种写法

引言 在实际的数字电路设计中,状态机是最常用的逻辑,而且往往是全部逻辑的核心部分,所以状态机的质量,会在比较大的程度上影响整个电路的质量. 本小节我们通过一个简单的例子(三进制脉动计数器)来说明一下状态机的4中写法. 1,模块功能 由于我们的目的在于说明状态机的写作方式,所以其逻辑越简单有利于理解.就是一个简单的脉动计数器,每个三个使能信号输出一个标示信号. 2,一段式 状态机的写法,一般有四种,即一段式,两段式,三段式,四段式.对于一段式的写法,整个状态机的状态转移.转移条件.对应状态的输出都

Android学习笔记(3)——按钮点击注册事件的四种写法

搬运自本人博客,xge技术博客 http://www.xgezhang.com/android_button_onclick_4_ways.html Android下,按钮点击事件是在开发过程中经常会写到的东西.这里总结一下常见的四种写法: 界面代码就是一个button控件: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <RelativeLayout xmlns:android="http://schemas.android.com/apk/re

安卓中关于点击响应事件的四种写法(电话拨号器)

安卓中点击响应事件主要是用button响应事件,关于响应事件的大概有四种写法 1,,创建一个内部类,定义点击事件 2,创建一个匿名内部类,直接实现接口 3,让activity实现点击事件的接口(用的最多常见的情况) 4,4,在布局文件里面绑定一个点击的方法 < Button android:onClick= "dailButtonClicked" ..... /> 本次过程的一些代码是基于简单的电话拨号器的实现的 public class MainActivity exte

Android代码规范----按钮单击事件的四种写法

[前言] 按钮少的时候用第三种的匿名内部类会比较快,比如写demo测试的时候或者登陆界面之类. 按钮多的时候一般选择第四种写法. 一.第一种写法:在XML文件中指定(很少用) 在XML文件中显式指定控件的onClick属性,点击按钮时会利用反射的方式调用对应Activity中的onClick()方法. (1)xml文件代码如下: 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2

Android中点击事件的四种写法详解

Android中点击事件的四种写法使用内部类实现点击事件使用匿名内部类实现点击事件让MainActivity实现View.OnClickListener接口通过布局文件中控件的属性 第一种方法:使用内部类基本步骤如下: 新建一个MyOnClickListener类并实现View.OnClickListener接口 重写View.OnClickListener接口中的OnClick(View view)方法 给Button绑定一个监听器,并监听一个点击事件示例代码如下: public class

Android点击事件(click button)的四种写法

在学习android开发和测试的时候发现不同的人对于click事件的写法是不一样的,上网查了一下,发现有四种写法,于是想比较一下四种方法的不同 第一种方法:匿名内部类 代码: package com.zdx.testdemo1; import javax.security.auth.PrivateCredentialPermission; import android.app.Activity;import android.os.Bundle;import android.view.Menu;i

button单击事件的四种写法

Button单击事件的四种写法:  1.第一种写法:匿名内部类 附上代码: public class MainActivity extends Activity{ private Button btn ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn = (B