1、通道(Channel):由java.nio.channels包定義的 。Channel 表示 IO 源與目標打開的鏈接。java
Channel 相似於傳統的 ‘流’。只不過 Channel 自己不能直接訪問數據,Channel只能與Buffer進行交互數組
2、 /*通道的主要實現類*/緩存
Java 爲 Channel 接口提供的 最主要實現類以下:網絡
FileChannel:用於讀取、寫入、映射和操做文件的通道app
SocketChannel:經過TCP 讀寫網絡中的數據dom
ServerSocketChannel:能夠監聽新進來的TCP鏈接,對每個新進來的鏈接都會建立一個 SocketChannel
工具
3、 /*如何獲取通道*/編碼
獲取通道spa
* 1.Java針對 支持通道的類提供了 getChannel()方法3d
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* 網絡IO:
* Socket
* ServerSocket
* DatagramSocket
2.在 JDK1.7 中 的 NIO.2 針對各個通道提供了靜態方法 open()
3.在 JDK1.7 中 的 NIO.2 的 File 工具類的newByteChannel()
利用通道進行數據傳輸
4、 /*通道之間的數據傳輸*/
transferForm() 將數據從源通道 傳輸到其餘 Channel中
transferTo() 其餘 Channel 從 原通道中 獲取數據
5、 /*分散(Scatter) 與 彙集(Gather)*/
分散讀取(Scattering Reads):將通道中的數據分散到多個緩衝區
彙集寫入(Gathering Writes):將多個緩衝區中的 數據 彙集到通道中
6、 /*字符集:Charset*/
編碼:字符串 -> 字節數組
解碼: 字節數組 -> 字符串
1 /* 2 * 1、通道(Channel):用於源節點 與目標節點的鏈接 ,在java nio 中 負責緩衝區中數據的傳輸。Channel 自己不存儲數據,所以須要配合緩衝區進行傳輸 3 * 4 * 2、通道的主要實現類 5 * java.nio.channels.Channel 接口 6 * |--FileChannel 7 * |--SocketChannel 8 * |--ServerSocketChannel 9 * |--DatagramChannel 10 * 11 * 3、獲取通道 12 * 1.Java針對 支持通道的類提供了 getChannel()方法 13 * 本地IO: 14 * FileInputStream/FileOutputStream 15 * RandomAccessFile 16 * 17 * 網絡IO: 18 * Socket 19 * ServerSocket 20 * DatagramSocket 21 * 22 * 2.在 JDK1.7 中 的 NIO.2 針對各個通道提供了靜態方法 open() 23 * 24 * 3.在 JDK1.7 中 的 NIO.2 的 File 工具類的newByteChannel() 25 * 26 * 4、通道之間的數據傳輸 27 * transferForm() 28 * transferTo() 29 * 30 * 5、分散(Scatter) 與 彙集(Gather) 31 * 分散讀取(Scattering Reads):將通道中的數據分散到多個緩衝區 32 * 彙集寫入(Gathering Writes):將多個緩衝區中的 數據 彙集到通道中 33 * 34 * 6、字符集:Charset 35 * 編碼:字符串 -> 字節數組 36 * 解碼: 字節數組 -> 字符串 37 * 38 * */ 39 public class TestChannel { 40 41 //使用指定字符集 進行編碼 和 解碼 42 @Test 43 public void test6() throws IOException { 44 //1.選擇字符集 45 Charset charset1 = Charset.forName("GBK"); 46 47 //2.獲取編碼器 48 CharsetEncoder encoder = charset1.newEncoder(); 49 50 //3.獲取解碼器 51 CharsetDecoder decoder = charset1.newDecoder(); 52 53 //4.建立字符串緩衝區,放入須要編碼的字符串 54 CharBuffer charBuffer = CharBuffer.allocate(1024); 55 charBuffer.put("迅雷影音"); 56 57 //5.對字符串進行編碼 (編碼:字符串 -> 字節數組) 58 charBuffer.flip(); //操做字符串緩衝區,解碼字符串以前 須要 flip 一下 59 ByteBuffer byteBuffer = encoder.encode(charBuffer); 60 61 // byteBuffer 此時 是 初始狀態,即position 是0 62 //調用 這個 for ,每 get 一次,position + 1 63 //這樣才能 在 flip 以後, 解碼 須要操做的數據 64 for(int i = 0;i<8;i++) { 65 System.out.println(byteBuffer.position()); 66 System.out.println(byteBuffer.get()); 67 } 68 69 //6.對字節數組進行解碼 (解碼: 字節數組 -> 字符串) 70 byteBuffer.flip(); //操做字節緩衝區,解碼字節數組以前 須要 flip 一下 71 CharBuffer charBuffer2 = decoder.decode(byteBuffer); 72 73 //打印解碼後的數據 74 System.out.println(charBuffer2.toString()); 75 } 76 77 //5.顯示全部的字符集 78 @Test 79 public void test5() { 80 Map<String,Charset> map = Charset.availableCharsets(); 81 Set<Entry<String, Charset>> set = map.entrySet(); 82 83 for(Entry<String, Charset> entry:set) { 84 System.out.println(entry.getKey() + " = " + entry.getValue()); 85 } 86 } 87 88 //4.分散和 彙集 (多個緩衝區) 89 @Test 90 public void test4() throws IOException { 91 // "rw" 是指 具備read 和 write 的 權限 92 RandomAccessFile raf = new RandomAccessFile("1.txt", "rw"); 93 //1.獲取通道 94 FileChannel channel1 = raf.getChannel(); 95 96 //2.分配指定大小的緩衝區 (多個) 97 ByteBuffer buf1 = ByteBuffer.allocate(100); 98 ByteBuffer buf2 = ByteBuffer.allocate(1024); 99 ByteBuffer[] bufs = {buf1,buf2}; 100 101 102 //4.彙集寫入 103 RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw"); 104 FileChannel channel2 = raf2.getChannel(); 105 106 107 //3.分散讀取 108 while(channel1.read(bufs)!= -1) { 109 for(ByteBuffer buf:bufs) { 110 buf.flip(); 111 } 112 //4.彙集寫入 113 channel2.write(bufs); 114 115 System.out.println("-----------------緩衝區1---------------"); 116 System.out.println(new String(bufs[0].array(),0,bufs[0].limit()) ); 117 System.out.println("-----------------緩衝區1---------------"); 118 119 System.out.println("-----------------緩衝區2---------------"); 120 System.out.println(new String(bufs[1].array(),0,bufs[1].limit())); 121 System.out.println("-----------------緩衝區2---------------"); 122 123 for(ByteBuffer buf:bufs) { 124 buf.clear(); 125 } 126 127 128 } 129 130 } 131 132 //3.通道之間的數據傳輸 133 @Test 134 public void test3() throws Exception { 135 FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); 136 FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE); 137 138 //直接使用transferTo 或者 transferFrom 完成通道之間的數據傳輸 139 inChannel.transferTo(0, inChannel.size(), outChannel); 140 outChannel.transferFrom(inChannel, 0, inChannel.size()); 141 142 inChannel.close(); 143 outChannel.close(); 144 } 145 146 //2.使用直接緩衝區完成文件的複製(內存映射文件)(這種方式效率更高) 147 //會出現的問題 :文件傳輸已經完成,可是程序仍然沒有結束,由於 java 虛擬機沒法及時 對 內存映射文件進行 進行釋放,必需要等指向映射文件的那個變量被回收 148 @Test 149 public void test2() { 150 151 long start = System.currentTimeMillis(); 152 153 FileChannel inChannel = null; 154 FileChannel outChannel = null; 155 MappedByteBuffer inMapperBuf = null; 156 MappedByteBuffer outMapperBuf = null; 157 158 try { 159 //使用 FileChannel 的 open方法 (能夠不用建立流就能夠獲得通道) 160 inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ); 161 outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE); 162 163 //內存映射文件 (也是一個 緩衝區 ,繼承自 ByteBuffer,直接緩衝區也只能使用 ByteBuffer) 164 inMapperBuf = inChannel.map(MapMode.READ_ONLY,0 , inChannel.size()); 165 outMapperBuf = outChannel.map(MapMode.READ_WRITE,0 , inChannel.size()); 166 167 } catch (IOException e) { 168 e.printStackTrace(); 169 } 170 171 172 //直接對緩衝區進行數據讀寫操做 173 byte[] bytes = new byte[inMapperBuf.limit()]; 174 inMapperBuf.get(bytes); 175 outMapperBuf.put(bytes); 176 177 try { 178 if(inChannel != null) { 179 inChannel.close(); 180 } 181 if(outChannel != null) { 182 outChannel.close(); 183 } 184 } catch (IOException e) { 185 e.printStackTrace(); 186 } 187 188 long end = System.currentTimeMillis(); 189 System.out.println("花費:" + (end-start)); 190 191 } 192 193 //1.利用通道完成文件的複製 194 @Test 195 public void test1() { 196 long start = System.currentTimeMillis(); 197 198 FileInputStream fis = null; 199 FileOutputStream fos = null; 200 try { 201 fis = new FileInputStream("1.jpg"); 202 fos = new FileOutputStream("2.jpg"); 203 } catch (FileNotFoundException e) { 204 e.printStackTrace(); 205 } 206 207 //1.獲取流對應的 通道 208 FileChannel inChannel = fis.getChannel(); 209 FileChannel outChannel = fos.getChannel(); 210 211 //2.分配指定大小的緩衝區 212 ByteBuffer buffer = ByteBuffer.allocate(1024); 213 214 //3.將通道中的數據存入緩存區 215 try { 216 //read 方法,從Channel 中讀取數據到 ByteBuffer (即往 緩衝區中 put 數據),因此不用 flip 217 while(inChannel.read(buffer) != -1) { 218 buffer.flip(); //切換到讀取數據模式 219 220 //4.將緩存區中的數據寫入通道中 (須要get 出 緩衝區中的 數據 ,因此須要 flip) 221 outChannel.write(buffer); 222 buffer.clear(); //清空緩衝區,使其繼續循環 223 } 224 } catch (IOException e) { 225 e.printStackTrace(); 226 } finally { 227 if(inChannel != null) { 228 try { 229 inChannel.close(); 230 } catch (IOException e) { 231 e.printStackTrace(); 232 } 233 } 234 if(outChannel != null) { 235 try { 236 outChannel.close(); 237 } catch (IOException e) { 238 e.printStackTrace(); 239 } 240 } 241 if(fis != null) { 242 try { 243 fis.close(); 244 } catch (IOException e) { 245 e.printStackTrace(); 246 } 247 } 248 if(fos != null) { 249 try { 250 fos.close(); 251 } catch (IOException e) { 252 e.printStackTrace(); 253 } 254 } 255 } 256 257 long end = System.currentTimeMillis(); 258 System.out.println("花費:" + (end-start)); 259 } 260 261 }