3.通道 Channel
一、通道(Channel):由java.nio.channels包定義的 。Channel 表示 IO 源與目標打開的連接。
Channel 類似于傳統(tǒng)的 ‘流’。只不過 Channel 本身不能直接訪問數(shù)據(jù),Channel只能與Buffer進行交互
?
二、 /*通道的主要實現(xiàn)類*/
Java 為 Channel 接口提供的 最主要實現(xiàn)類如下:
FileChannel:用于讀取、寫入、映射和操作文件的通道
SocketChannel:通過TCP 讀寫網(wǎng)絡中的數(shù)據(jù)
ServerSocketChannel:可以監(jiān)聽新進來的TCP連接,對每一個新進來的連接都會創(chuàng)建一個 SocketChannel
?
三、 /*如何獲取通道*/
獲取通道
* 1.Java針對 支持通道的類提供了 getChannel()方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* 網(wǎng)絡IO:
* Socket
* ServerSocket
* DatagramSocket
2.在 JDK1.7 中 的 NIO.2 針對各個通道提供了靜態(tài)方法 open()
3.在 JDK1.7 中 的 NIO.2 的 File 工具類的newByteChannel()
?
利用通道進行數(shù)據(jù)傳輸
?
四、 /*通道之間的數(shù)據(jù)傳輸*/
transferForm() 將數(shù)據(jù)從源通道 傳輸?shù)狡渌?Channel中
transferTo() 其他 Channel 從 原通道中 獲取數(shù)據(jù)
五、 /*分散(Scatter) 與 聚集(Gather)*/
分散讀取(Scattering Reads):將通道中的數(shù)據(jù)分散到多個緩沖區(qū)
聚集寫入(Gathering Writes):將多個緩沖區(qū)中的 數(shù)據(jù) 聚集到通道中
六、 /*字符集:Charset*/
編碼:字符串 -> 字節(jié)數(shù)組
解碼: 字節(jié)數(shù)組 -> 字符串
?
1 /* 2 * 一、通道(Channel):用于源節(jié)點 與目標節(jié)點的連接 ,在java nio 中 負責緩沖區(qū)中數(shù)據(jù)的傳輸。Channel 本身不存儲數(shù)據(jù),因此需要配合緩沖區(qū)進行傳輸 3 * 4 * 二、通道的主要實現(xiàn)類 5 * java.nio.channels.Channel 接口 6 * |--FileChannel 7 * |--SocketChannel 8 * |--ServerSocketChannel 9 * |--DatagramChannel 10 * 11 * 三、獲取通道 12 * 1.Java針對 支持通道的類提供了 getChannel()方法 13 * 本地IO: 14 * FileInputStream/FileOutputStream 15 * RandomAccessFile 16 * 17 * 網(wǎng)絡IO: 18 * Socket 19 * ServerSocket 20 * DatagramSocket 21 * 22 * 2.在 JDK1.7 中 的 NIO.2 針對各個通道提供了靜態(tài)方法 open() 23 * 24 * 3.在 JDK1.7 中 的 NIO.2 的 File 工具類的newByteChannel() 25 * 26 * 四、通道之間的數(shù)據(jù)傳輸 27 * transferForm() 28 * transferTo() 29 * 30 * 五、分散(Scatter) 與 聚集(Gather) 31 * 分散讀取(Scattering Reads):將通道中的數(shù)據(jù)分散到多個緩沖區(qū) 32 * 聚集寫入(Gathering Writes):將多個緩沖區(qū)中的 數(shù)據(jù) 聚集到通道中 33 * 34 * 六、字符集:Charset 35 * 編碼:字符串 -> 字節(jié)數(shù)組 36 * 解碼: 字節(jié)數(shù)組 -> 字符串 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.創(chuàng)建字符串緩沖區(qū),放入需要編碼的字符串 54 CharBuffer charBuffer = CharBuffer.allocate(1024); 55 charBuffer.put("迅雷影音"); 56 57 //5.對字符串進行編碼 (編碼:字符串 -> 字節(jié)數(shù)組) 58 charBuffer.flip(); //操作字符串緩沖區(qū),解碼字符串之前 需要 flip 一下 59 ByteBuffer byteBuffer = encoder.encode(charBuffer); 60 61 // byteBuffer 此時 是 初始狀態(tài),即position 是0 62 //調(diào)用 這個 for ,每 get 一次,position + 1 63 //這樣才能 在 flip 之后, 解碼 需要操作的數(shù)據(jù) 64 for(int i = 0;i<8;i++) { 65 System.out.println(byteBuffer.position()); 66 System.out.println(byteBuffer.get()); 67 } 68 69 //6.對字節(jié)數(shù)組進行解碼 (解碼: 字節(jié)數(shù)組 -> 字符串) 70 byteBuffer.flip(); //操作字節(jié)緩沖區(qū),解碼字節(jié)數(shù)組之前 需要 flip 一下 71 CharBuffer charBuffer2 = decoder.decode(byteBuffer); 72 73 //打印解碼后的數(shù)據(jù) 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.分散和 聚集 (多個緩沖區(qū)) 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.分配指定大小的緩沖區(qū) (多個) 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("-----------------緩沖區(qū)1---------------"); 116 System.out.println(new String(bufs[0].array(),0,bufs[0].limit()) ); 117 System.out.println("-----------------緩沖區(qū)1---------------"); 118 119 System.out.println("-----------------緩沖區(qū)2---------------"); 120 System.out.println(new String(bufs[1].array(),0,bufs[1].limit())); 121 System.out.println("-----------------緩沖區(qū)2---------------"); 122 123 for(ByteBuffer buf:bufs) { 124 buf.clear(); 125 } 126 127 128 } 129 130 } 131 132 //3.通道之間的數(shù)據(jù)傳輸 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 完成通道之間的數(shù)據(jù)傳輸 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.使用直接緩沖區(qū)完成文件的復制(內(nèi)存映射文件)(這種方式效率更高) 147 //會出現(xiàn)的問題 :文件傳輸已經(jīng)完成,但是程序仍然沒有結束,因為 java 虛擬機無法及時 對 內(nèi)存映射文件進行 進行釋放,必須要等指向映射文件的那個變量被回收 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方法 (可以不用創(chuàng)建流就可以得到通道) 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 //內(nèi)存映射文件 (也是一個 緩沖區(qū) ,繼承自 ByteBuffer,直接緩沖區(qū)也只能使用 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 //直接對緩沖區(qū)進行數(shù)據(jù)讀寫操作 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.分配指定大小的緩沖區(qū) 212 ByteBuffer buffer = ByteBuffer.allocate(1024); 213 214 //3.將通道中的數(shù)據(jù)存入緩存區(qū) 215 try { 216 //read 方法,從Channel 中讀取數(shù)據(jù)到 ByteBuffer (即往 緩沖區(qū)中 put 數(shù)據(jù)),所以不用 flip 217 while(inChannel.read(buffer) != -1) { 218 buffer.flip(); //切換到讀取數(shù)據(jù)模式 219 220 //4.將緩存區(qū)中的數(shù)據(jù)寫入通道中 (需要get 出 緩沖區(qū)中的 數(shù)據(jù) ,所以需要 flip) 221 outChannel.write(buffer); 222 buffer.clear(); //清空緩沖區(qū),使其繼續(xù)循環(huán) 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 }?
轉(zhuǎn)載于:https://www.cnblogs.com/xuzekun/p/7435504.html
總結
以上是生活随笔為你收集整理的3.通道 Channel的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java web轻量级开发面试教程内容精
- 下一篇: js获取当前日期方法