文件通道總是阻塞式的。 文件通道不能創建,只能通過(RandomAccessFile、FileInputStream、FileOutputStream)getChannel()獲得,具有與File形同的訪問權限。 線程安全。 文件鎖:鎖的對象是文件。
1 package org.windwant.nio;
2
3
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.io.RandomAccessFile;
8 import java.nio.ByteBuffer;
9 import java.nio.MappedByteBuffer;
10 import java.nio.channels.Channel;
11 import java.nio.channels.FileChannel;
12 import java.nio.channels.FileLock;
13 import java.nio.channels.Selector;
14 import java.util.concurrent.locks.ReadWriteLock;
15 import java.util.concurrent.locks.ReentrantReadWriteLock;
16
17 /**
18 * Created by windwant on 2016/5/13.
19 */
20 public class NIOOpt {
21
22 public static void main(String[] args) {
23 try {
24 MappedPrivateChannel();
25 } catch (Exception e) {
26 e.printStackTrace();
27 }
28 }
29
30 /**
31 * MapMode.PRIVATE 寫時拷貝(copy-on-write)映射:通過put()修改的任何修改,會導致產生一個私有的數據
32 * 拷貝,寶貝中的數據只有MappedByteBuffer實例可以看到。不會對底層文件做任何修改。若緩沖區被回收,修改丟
33 * 失,read/write方式建立通道。
34 * 做修改,拷貝副本前,其它方式的映射區的修改,會反映到當前區域。映射相互的修改不可見
35 * 允許父子進程共享內存頁
36 * 處理一個文件多個映射場景。
37 * 關閉通道,映射會保持。除非丟棄緩沖區本身。
38 * MappedByteBuffer 對象是直接的,占用的內存位於jvm堆棧之外。
39 */
40 public static void MappedPrivateChannel() throws Exception {
41 // Create a temp file and get a channel connected to it
42 File tempFile = File.createTempFile ("mmaptest", null);
43 RandomAccessFile file = new RandomAccessFile (tempFile, "rw");
44 FileChannel channel = file.getChannel( );
45 ByteBuffer temp = ByteBuffer.allocate (100);
46 // Put something in the file, starting at location 0
47 temp.put ("This is the file content".getBytes( ));
48 temp.flip( );
49 channel.write (temp, 0);
50 // Put something else in the file, starting at location 8192.
51 // 8192 is 8 KB, almost certainly a different memory/FS page.
52 // This may cause a file hole, depending on the
53 // filesystem page size.
54 temp.clear( );
55 temp.put ("This is more file content".getBytes( ));
56 temp.flip( );
57 channel.write (temp, 8192);
58 // Create three types of mappings to the same file
59 MappedByteBuffer ro = channel.map (
60 FileChannel.MapMode.READ_ONLY, 0, channel.size( ));
61 MappedByteBuffer rw = channel.map (
62 FileChannel.MapMode.READ_WRITE, 0, channel.size( ));
63 MappedByteBuffer cow = channel.map (
64 FileChannel.MapMode.PRIVATE, 0, channel.size( ));
65 // the buffer states before any modifications
66 System.out.println ("Begin");
67 showBuffers (ro, rw, cow);
68 // Modify the copy-on-write buffer
69 cow.position (8);
70 cow.put ("COW".getBytes( ));
71 System.out.println ("Change to COW buffer");
72 showBuffers (ro, rw, cow);
73 // Modify the read/write buffer92
74 rw.position (9);
75 rw.put (" R/W ".getBytes( ));
76 rw.position (8194);
77 rw.put (" R/W ".getBytes( ));
78 rw.force( );
79 System.out.println ("Change to R/W buffer");
80 showBuffers (ro, rw, cow);
81 // Write to the file through the channel; hit both pages
82 temp.clear( );
83 temp.put ("Channel write ".getBytes( ));
84 temp.flip( );
85 channel.write (temp, 0);
86 temp.rewind( );
87 channel.write (temp, 8202);
88 System.out.println ("Write on channel");
89 showBuffers (ro, rw, cow);
90 // Modify the copy-on-write buffer again
91 cow.position (8207);
92 cow.put (" COW2 ".getBytes( ));
93 System.out.println ("Second change to COW buffer");
94 showBuffers (ro, rw, cow);
95 // Modify the read/write buffer
96 rw.position (0);
97 rw.put (" R/W2 ".getBytes( ));
98 rw.position (8210);
99 rw.put (" R/W2 ".getBytes( ));
100 rw.force( );
101 System.out.println ("Second change to R/W buffer");
102 showBuffers (ro, rw, cow);
103 // cleanup
104 channel.close( );
105 file.close( );
106 tempFile.delete( );
107 }
108
109 // Show the current content of the three buffers
110 public static void showBuffers (ByteBuffer ro, ByteBuffer rw, ByteBuffer cow) throws Exception{
111 dumpBuffer ("R/O", ro);
112 dumpBuffer ("R/W", rw);
113 dumpBuffer ("COW", cow);
114 System.out.println ("");
115 }
116 // Dump buffer content, counting and skipping nulls
117 public static void dumpBuffer (String prefix, ByteBuffer buffer) throws Exception {
118 System.out.print (prefix + ": '");
119 int nulls = 0;
120 int limit = buffer.limit( );
121 for (int i = 0; i < limit; i++) {
122 char c = (char) buffer.get (i);
123 if (c == '\u0000') {
124 nulls++;
125 continue;
126 }
127 if (nulls != 0) {
128 System.out.print ("|[" + nulls
129 + " nulls]|");
130 nulls = 0;
131 }
132 System.out.print (c);
133 }
134 System.out.println ("'");
135 }
136
137 /**
138 * channel Gather/Scatter 矢量IO
139 */
140 public static void channelGatherScatter(){
141 ByteBuffer head = ByteBuffer.allocate(4);
142 ByteBuffer body = ByteBuffer.allocate(100);
143 RandomAccessFile afile = null;
144 RandomAccessFile bfile = null;
145 ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
146 try {
147 afile = new RandomAccessFile("hello.txt", "r");
148 bfile = new RandomAccessFile("hehe.txt", "rw");
149 readWriteLock.readLock().lock();
150 FileChannel fileChannel = afile.getChannel();
151 ByteBuffer[] buffers = {head, body};
152 while (fileChannel.read(buffers) != -1){
153 }
154 head.flip();
155 body.flip();
156 System.out.println(new String(head.array()));
157 System.out.println(new String(body.array()));
158 readWriteLock.readLock().unlock();
159 fileChannel.close();
160 afile.close();
161
162 readWriteLock.writeLock().lock();
163 FileChannel bfileChannel = bfile.getChannel();
164
165 while (bfileChannel.write(buffers) > 0){
166 }
167
168 bfileChannel.position(bfileChannel.position() + 10);
169 bfileChannel.write(ByteBuffer.wrap("THIS IS THE TEST TEXT!".getBytes()));
170 bfileChannel.truncate(3); //改變文件大小
171 bfileChannel.force(true); //寫入磁盤文件 參數 是否更新文件元數據(所有者、訪問權限等)
172 readWriteLock.writeLock().unlock();
173 bfileChannel.close();
174 bfile.close();
175 }catch (Exception e){
176 e.printStackTrace();
177 }
178 }
179
180 /**
181 * 基於MappedFileChannle的文件復制
182 * 文件鎖
183 */
184 public static void mappedFileChannelLock(){
185 RandomAccessFile afile = null;
186 RandomAccessFile bfile = null;
187 FileChannel fc = null;
188 FileChannel fcb = null;
189 try {
190 afile = new RandomAccessFile("hello.txt", "rw");
191 fc = afile.getChannel();
192 long length = fc.size();
193 FileLock fileLock = fc.tryLock(0, length, true);//true共享鎖 false 獨占鎖 從開始 鎖定全部內容 如果獲取不到鎖會返回null
194 if(null != fileLock) {
195 MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
196 byte[] fbo = new byte[(int) length];
197 mbb.get(fbo);
198 System.out.println(new String(fbo, "UTF-8"));
199 fileLock.release();
200 bfile = new RandomAccessFile("hehe.txt", "rw");
201 fcb = bfile.getChannel();
202 fileLock = fcb.tryLock(0, length, false);
203 MappedByteBuffer mbbb = fcb.map(FileChannel.MapMode.READ_WRITE, 0, length);
204
205 for (int i = 0; i < length; i++) {
206 mbbb.put(i, fbo[i]);
207 }
208 mbbb.flip();
209 mbbb.force();
210 fileLock.release();
211 }
212 } catch (FileNotFoundException e) {
213 e.printStackTrace();
214 } catch (IOException e) {
215 e.printStackTrace();
216 }finally {
217 try {
218 fc.close();
219 fcb.close();
220 afile.close();
221 bfile.close();
222 } catch (IOException e) {
223 e.printStackTrace();
224 }
225 }
226 }
227
228 /**
229 * MappedByteBuffer map(MapMode mode, long position, long size)
230 * size大於文件大小,文件會做擴充
231 * MappedByteBuffer 內存映射緩沖池
232 * 基於MappedFileChannle的文件復制
233 * 讀寫鎖
234 * 直接讀取,修改磁盤上的文件。
235 * 自動緩存內存頁,比較高效。
236 */
237 public static void mappedFileChannel(){
238 RandomAccessFile afile = null;
239 RandomAccessFile bfile = null;
240 FileChannel fc = null;
241 FileChannel fcb = null;
242 ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
243 try {
244 afile = new RandomAccessFile("hello.txt", "rw");
245 readWriteLock.readLock().lock();
246 fc = afile.getChannel();
247 long length = fc.size();
248 MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
249 byte[] fbo = new byte[(int) length];
250 mbb.get(fbo);
251 System.out.println(new String(fbo));
252 readWriteLock.readLock().unlock();
253 bfile = new RandomAccessFile("hehe.txt", "rw");
254 readWriteLock.writeLock().lock();
255 fcb = bfile.getChannel();
256 MappedByteBuffer mbbb = fcb.map(FileChannel.MapMode.READ_WRITE, 0, length);
257
258 for (int i = 0; i < length; i++) {
259 mbbb.put(i, fbo[i]);
260 }
261 mbbb.flip();
262 mbbb.force();
263 readWriteLock.writeLock().unlock();
264 } catch (FileNotFoundException e) {
265 e.printStackTrace();
266 } catch (IOException e) {
267 e.printStackTrace();
268 }finally {
269 try {
270 fc.close();
271 fcb.close();
272 afile.close();
273 bfile.close();
274 } catch (IOException e) {
275 e.printStackTrace();
276 }
277 }
278 }
279
280 /**
281 * FileChannel文件讀取
282 */
283 public static void fileChannel(){
284 try {
285 RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
286 FileChannel fc = afile.getChannel();
287 ByteBuffer bb = ByteBuffer.allocate(48);
288 int byteRead;
289 while ((byteRead = fc.read(bb)) != -1){//確保讀完
290 System.out.println("read:" + byteRead);
291 bb.flip();//翻轉為讀狀態
292 while (bb.hasRemaining()){//直到沒有可讀的字節
293 System.out.println(String.valueOf(bb.get()));
294 }
295 bb.clear();
296 }
297 fc.close();
298 afile.close();
299 } catch (FileNotFoundException e) {
300 e.printStackTrace();
301 } catch (IOException e) {
302 e.printStackTrace();
303 }
304 }
305
306 /**
307 * 基於FileChannel transferTo transferFrom 方法文件復制
308 */
309 public static void fileTransfer(){
310 try {
311 RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
312 RandomAccessFile bfile = new RandomAccessFile("hehe.txt", "rw");
313 FileChannel ac = afile.getChannel();
314 FileChannel bc = bfile.getChannel();
315 long position = 0;
316 long count = ac.size();
317 // bc.transferFrom(ac, position, count);
318 ac.transferTo(position, count, bc);
319 ac.close();
320 afile.close();
321 bc.close();
322 bfile.close();
323 } catch (FileNotFoundException e) {
324 e.printStackTrace();
325 } catch (IOException e) {
326 e.printStackTrace();
327 }
328 }
329
330 public static void fileSelector(){
331 try {
332 RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
333 Channel c = afile.getChannel();
334 Selector s = Selector.open();
335 } catch (FileNotFoundException e) {
336 e.printStackTrace();
337 } catch (IOException e) {
338 e.printStackTrace();
339 }
340 }
341
342 /**
343 * 基於基本channel buffer的文件復制操作
344 */
345 public static void fileTransferByNormal() {
346 try {
347 RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
348 RandomAccessFile bfile = new RandomAccessFile("hehe.txt", "rw");
349 FileChannel ac = afile.getChannel();
350 FileChannel bc = bfile.getChannel();
351
352 ByteBuffer bf = ByteBuffer.allocateDirect(16 * 1024);
353 while (ac.read(bf) != -1) {
354 bf.flip();
355 while (bf.hasRemaining()) {//確保寫完
356 bc.write(bf);
357 }
358 bf.clear();
359 }
360 ac.close();
361 afile.close();
362 bc.close();
363 bfile.close();
364 } catch (FileNotFoundException e) {
365 e.printStackTrace();
366 } catch (IOException e) {
367 e.printStackTrace();
368 }
369 }
370 }