3.通道 Channel

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 }
相關文章
相關標籤/搜索