![](https://i-blog.csdnimg.cn/blog_migrate/407ab0a12b9ac2a4df196cfd80a1356f.png)
文件通道总是阻塞式的。
文件通道不能创建,只能通过(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 }