天天看點

Java實作檔案拷貝

經過一組簡單的測試發現JAVA NIO提供的檔案記憶體映射方法實作檔案拷貝速度最快,不管是大檔案還是小檔案,特别是大檔案的拷貝速度比普通方法提高20倍,唯一有個前提就是記憶體需要足夠大,否則檔案映射肯定失敗(當然可以通過分割檔案,部分映射的方法避免,但就比較麻煩了);其次NIO提供的檔案管道傳輸速度也比較好,如果沒法做檔案記憶體映射,推薦這種拷貝方法;另外,Buffer的大小,對于讀寫速度還是有影響的,基本就是Buffer越大讀寫越快(有個疑問就是Buffer.allocateDirec()效率提高不明顯);最後,總體看來NIO的效率比老IO高,不管使用哪種方式,老IO使用流讀寫隻能一個位元組一個位元組的摳,NIO使用塊的方式讀寫還是相對比較快,是以沒有特别需求的情況下,推薦使用NIO,目前NIO基本能覆寫老IO的所有功能(當然NIO還提供N多新功能)。

測試環境

1

2

3

4

5

6

7

8

9

<code>Eclipse(Juno) JVM(Sun JDK1.</code><code>7</code><code>) 參數:</code>

<code>-Xms1536m</code>

<code>-Xmx1536m</code>

<code>-Xverify:none -XX:+UseParallelGC</code>

<code>-XX:PermSize=128M</code>

<code>-XX:MaxPermSize=128M</code>

<code>OS參數:</code>

<code>Win7 64Bit + 4GB</code>

<code>實體磁盤空間充足</code>

測試代碼

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

185

186

187

188

189

190

<code>import</code> <code>java.io.FileInputStream;</code>

<code>import</code> <code>java.io.FileNotFoundException;</code>

<code>import</code> <code>java.io.FileOutputStream;</code>

<code>import</code> <code>java.io.IOException;</code>

<code>import</code> <code>java.io.RandomAccessFile;</code>

<code>import</code> <code>java.nio.ByteBuffer;</code>

<code>import</code> <code>java.nio.MappedByteBuffer;</code>

<code>import</code> <code>java.nio.channels.FileChannel;</code>

<code>public</code> <code>class</code> <code>FileCopy {</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>BUFFER_SIZE_1024 = </code><code>1024</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>BUFFER_SIZE_4096 = </code><code>4096</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>int</code> <code>BUFFER_SIZE_10240 = </code><code>10240</code><code>;</code>

<code>       </code> 

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>String FROM_FILE_42MB = </code><code>"G:/from_42MB.rar"</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>final</code> <code>String FROM_FILE_1GB = </code><code>"G:/from_350MB.rar"</code><code>;</code>

<code>    </code><code>private</code> <code>static</code> <code>int</code> <code>BUFFER_SIZE = BUFFER_SIZE_1024;</code>

<code>    </code><code>private</code> <code>static</code> <code>String FROM_FILE = FROM_FILE_42MB;</code>

<code>    </code><code>/**</code>

<code>     </code><code>* @param args</code>

<code>     </code><code>* @throws Exception</code>

<code>     </code><code>*/</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) </code><code>throws</code> <code>Exception {</code>

<code>        </code><code>System.out.println(</code><code>"File :"</code> <code>+ FROM_FILE + </code><code>" ---- Buffer Size : "</code> <code>+ BUFFER_SIZE + </code><code>"--------------"</code><code>);</code>

<code>        </code><code>testFileCopy();</code>

<code>           </code> 

<code>        </code><code>BUFFER_SIZE = BUFFER_SIZE_4096;</code>

<code>        </code><code>BUFFER_SIZE = BUFFER_SIZE_10240;</code>

<code>        </code><code>BUFFER_SIZE = BUFFER_SIZE_1024;</code>

<code>        </code><code>FROM_FILE = FROM_FILE_1GB;</code>

<code>    </code><code>}</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>testFileCopy() </code><code>throws</code> <code>FileNotFoundException,</code>

<code>            </code><code>IOException {</code>

<code>        </code><code>coypByMbb();</code>

<code>        </code><code>copyByNioTransferFrom();</code>

<code>        </code><code>copyByNioTransferTo();</code>

<code>        </code><code>coypByBufferRead();</code>

<code>        </code><code>coypByFastBufferRead();           </code>

<code>        </code><code>coypByStream();</code><code>//Old IO style</code>

<code>     </code><code>* 使用FileChannel.transferFrom()實作</code>

<code>     </code><code>* @throws FileNotFoundException</code>

<code>     </code><code>* @throws IOException</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>copyByNioTransferFrom() </code><code>throws</code> <code>FileNotFoundException,</code>

<code>        </code><code>long</code> <code>startTime = System.currentTimeMillis();</code>

<code>        </code><code>RandomAccessFile fromFile = </code><code>new</code> <code>RandomAccessFile(FROM_FILE, </code><code>"rw"</code><code>);</code>

<code>        </code><code>FileChannel fromChannel = fromFile.getChannel();</code>

<code>        </code><code>RandomAccessFile toFile = </code><code>new</code> <code>RandomAccessFile(</code><code>"G:/to1.rar"</code><code>, </code><code>"rw"</code><code>);</code>

<code>        </code><code>FileChannel toChannel = toFile.getChannel();</code>

<code>        </code><code>long</code> <code>position = </code><code>0</code><code>;</code>

<code>        </code><code>long</code> <code>count = fromChannel.size();</code>

<code>        </code><code>toChannel.transferFrom(fromChannel, position, count);</code>

<code>        </code><code>long</code> <code>endTime = System.currentTimeMillis();</code>

<code>        </code><code>System.out.println(</code><code>"copyByNioTransferFrom time consumed(buffer size no effect) : "</code>

<code>                </code><code>+ (endTime - startTime));</code>

<code>     </code><code>* 使用FileChannel.transferTo()實作</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>copyByNioTransferTo() </code><code>throws</code> <code>FileNotFoundException,</code>

<code>        </code><code>RandomAccessFile toFile = </code><code>new</code> <code>RandomAccessFile(</code><code>"G:/to2.rar"</code><code>, </code><code>"rw"</code><code>);</code>

<code>        </code><code>fromChannel.transferTo(position, count, toChannel);</code>

<code>        </code><code>System.out.println(</code><code>"copyByNioTransferTo time consumed(buffer size no effect) : "</code>

<code>     </code><code>* 使用Channel, Buffer簡單讀寫實作</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>coypByBufferRead() </code><code>throws</code> <code>IOException {</code>

<code>        </code><code>FileInputStream fin = </code><code>new</code> <code>FileInputStream(FROM_FILE);</code>

<code>        </code><code>FileOutputStream fout = </code><code>new</code> <code>FileOutputStream(</code><code>"G:/to3.rar"</code><code>);</code>

<code>        </code><code>FileChannel fcin = fin.getChannel();</code>

<code>        </code><code>FileChannel fcout = fout.getChannel();</code>

<code>        </code><code>ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);</code>

<code>        </code><code>while</code> <code>(</code><code>true</code><code>) {</code>

<code>            </code><code>buffer.clear();</code>

<code>            </code><code>int</code> <code>r = fcin.read(buffer);</code>

<code>            </code><code>if</code> <code>(r == -</code><code>1</code><code>) {</code>

<code>                </code><code>break</code><code>;</code>

<code>            </code><code>}</code>

<code>            </code><code>buffer.flip();</code>

<code>            </code><code>fcout.write(buffer);</code>

<code>        </code><code>}</code>

<code>        </code><code>System.out.println(</code><code>"coypByBufferRead time consumed(buffer size take effect) : "</code>

<code>     </code><code>* 使用連續記憶體的Buffer實作</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>coypByFastBufferRead() </code><code>throws</code> <code>IOException {</code>

<code>        </code><code>FileOutputStream fout = </code><code>new</code> <code>FileOutputStream(</code><code>"G:/to4.rar"</code><code>);</code>

<code>        </code><code>ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);</code>

<code>        </code><code>System.out.println(</code><code>"coypByFastBufferRead time consumed(buffer size take effect) : "</code>

<code>     </code><code>* 使用檔案記憶體映射實作</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>coypByMbb() </code><code>throws</code> <code>IOException {</code>

<code>        </code><code>RandomAccessFile fout = </code><code>new</code> <code>RandomAccessFile(</code><code>"G:/to5.rar"</code><code>, </code><code>"rw"</code><code>);</code>

<code>        </code><code>MappedByteBuffer mbbi = fcin.map(FileChannel.MapMode.READ_ONLY, </code><code>0</code><code>,</code>

<code>                </code><code>fcin.size());</code>

<code>        </code><code>MappedByteBuffer mbbo = fcout.map(FileChannel.MapMode.READ_WRITE, </code><code>0</code><code>,</code>

<code>        </code><code>mbbo.put(mbbi);</code>

<code>        </code><code>mbbi.clear();</code>

<code>        </code><code>mbbo.clear();</code>

<code>        </code><code>System.out</code>

<code>                </code><code>.println(</code><code>"coypByMbb time consumed(buffer size no effect) : "</code> <code>+ (endTime - startTime));</code>

<code>     </code><code>* 使用傳統IO的流讀寫方式實作</code>

<code>    </code><code>private</code> <code>static</code> <code>void</code> <code>coypByStream() </code><code>throws</code> <code>IOException {</code>

<code>        </code><code>FileOutputStream fout = </code><code>new</code> <code>FileOutputStream(</code><code>"G:/to6.rar"</code><code>);</code>

<code>        </code><code>byte</code><code>[] buffer = </code><code>new</code> <code>byte</code><code>[BUFFER_SIZE];</code>

<code>            </code><code>int</code> <code>ins = fin.read(buffer);</code>

<code>            </code><code>if</code> <code>(ins == -</code><code>1</code><code>) {</code>

<code>                </code><code>fin.close();</code>

<code>                </code><code>fout.flush();</code>

<code>                </code><code>fout.close();</code>

<code>            </code><code>} </code><code>else</code><code>{</code>

<code>                </code><code>fout.write(buffer, </code><code>0</code><code>, ins);</code>

<code>            </code><code>}             </code>

<code>        </code><code>System.out.println(</code><code>"coypByStream time consumed(buffer size take effect) : "</code> <code>+ (endTime - startTime));</code>

<code>}</code>

測試結果

<code>File :G:/from_42MB.rar ---- Buffer Size : </code><code>1024</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>47</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>62</code>

<code>copyByNioTransferTo time consumed(buffer size no effect) : </code><code>47</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>249</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>188</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>187</code>

<code>         </code> 

<code>File :G:/from_42MB.rar ---- Buffer Size : </code><code>4096</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>15</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>16</code>

<code>copyByNioTransferTo time consumed(buffer size no effect) : </code><code>31</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>125</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>79</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>93</code>

<code>File :G:/from_42MB.rar ---- Buffer Size : </code><code>10240</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>16</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>32</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>78</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>62</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>63</code>

<code>File :G:/from_350MB.rar ---- Buffer Size : </code><code>1024</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>280</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>453</code>

<code>copyByNioTransferTo time consumed(buffer size no effect) : </code><code>7785</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>8144</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>7068</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>8503</code>

<code>File :G:/from_350MB.rar ---- Buffer Size : </code><code>4096</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>1904</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>5978</code>

<code>copyByNioTransferTo time consumed(buffer size no effect) : </code><code>7379</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>7621</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>7474</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>8200</code>

<code>File :G:/from_350MB.rar ---- Buffer Size : </code><code>10240</code><code>--------------</code>

<code>coypByMbb time consumed(buffer size no effect) : </code><code>328</code>

<code>copyByNioTransferFrom time consumed(buffer size no effect) : </code><code>6864</code>

<code>copyByNioTransferTo time consumed(buffer size no effect) : </code><code>7021</code>

<code>coypByBufferRead time consumed(buffer size take effect) : </code><code>7199</code>

<code>coypByFastBufferRead time consumed(buffer size take effect) : </code><code>7941</code>

<code>coypByStream time consumed(buffer size take effect) : </code><code>7801</code>

<code></code>

     本文轉自sarchitect 51CTO部落格,原文連結:http://blog.51cto.com/stevex/1272956,如需轉載請自行聯系原作者