3.通道 Channel

一、通道(Channel):由java.nio.channels包定义的 。Channel 表示 IO 源与目标打开的连接。

Channel 类似于传统的 ‘流’。只不过 Channel 本身不能直接访问数据,Channel只能与Buffer进行交互

二、 /*通道的主要实现类*/

Java 为 Channel 接口提供的 最主要实现类如下:

  FileChannel:用于读取、写入、映射和操作文件的通道

  SocketChannel:通过TCP 读写网络中的数据

  ServerSocketChannel:可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个 SocketChannel

三、 /*如何获取通道*/

获取通道

  * 1.Java针对 支持通道的类提供了 getChannel()方法

    * 本地IO:

      * FileInputStream/FileOutputStream

      * RandomAccessFile

    * 网络IO:

      * Socket

      * ServerSocket

      * DatagramSocket

  2.在 JDK1.7 中 的 NIO.2 针对各个通道提供了静态方法 open()

  3.在 JDK1.7 中 的 NIO.2 的 File 工具类的newByteChannel()

利用通道进行数据传输

四、 /*通道之间的数据传输*/

  transferForm() 将数据从源通道 传输到其他 Channel中

  transferTo() 其他 Channel 从 原通道中 获取数据

  

五、 /*分散(Scatter) 与 聚集(Gather)*/

  分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区

  聚集写入(Gathering Writes):将多个缓冲区中的 数据 聚集到通道中

  
六、 /*字符集:Charset*/

  编码:字符串 -> 字节数组

  解码: 字节数组 -> 字符串
  

  1 /*
  2  * 一、通道(Channel):用于源节点 与目标节点的连接 ,在java nio 中 负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输
  3  *
  4  * 二、通道的主要实现类
  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  *   网络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  * 四、通道之间的数据传输
 27  * transferForm()
 28  * transferTo()
 29  *
 30  * 五、分散(Scatter) 与 聚集(Gather)
 31  * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区
 32  * 聚集写入(Gathering Writes):将多个缓冲区中的 数据 聚集到通道中
 33  *
 34  * 六、字符集: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 }

  

时间: 2024-10-05 04:58:17

3.通道 Channel的相关文章

nio再学习之通道channel

通道(Channel):用于在数据传输过程中,进行输入输出的通道,其与(流)Stream不一样,流是单向的,在BIO中我们分为输入流,输出流,但是在通道中其又具有读的功能也具有写的功能或者两者同时进行. 通道主要分为以下几类: 服务器相关: ServerSocketChannel: SocketChannel: 文件相关: FIleChannel: 多线程通信相关: DatagramChannel 相关的类图关系 原文地址:https://www.cnblogs.com/lonecloud/p/

golang协程——通道channel阻塞

新的一年开始了,不管今天以前发生了什么,向前看,就够了. 说到channel,就一定要说一说线程了.任何实际项目,无论大小,并发是必然存在的.并发的存在,就涉及到线程通信.在当下的开发语言中,线程通讯主要有两种,共享内存与消息传递.共享内存一定都很熟悉,通过共同操作同一对象,实现线程间通讯.消息传递即通过类似聊天的方式.golang对并发的处理采用了协程的技术.golang的goroutine就是协程的实现.协程的概念很早就有,简单的理解为轻量级线程,goroutine就是为了解决并发任务间的通

Java NIO中的通道Channel(二)分散/聚集 Scatter/Gather

什么是Scatter/Gather scatter/gather指的在多个缓冲区上实现一个简单的I/O操作,比如从通道中读取数据到多个缓冲区,或从多个缓冲区中写入数据到通道: scatter(分散):指的是从通道中读取数据分散到多个缓冲区Buffer的过程,该过程会将每个缓存区填满,直至通道中无数据或缓冲区没有空间: gather(聚集):指的是将多个缓冲区Buffer聚集起来写入到通道的过程,该过程类似于将多个缓冲区的内容连接起来写入通道: scatter/gather接口 如下是Scatte

Java NIO之通道Channel

channel与流的区别: 流基于字节,且读写为单向的. 通道基于快Buffer,可以异步读写.除了FileChannel之外都是双向的.   channel的主要实现: FileChannel DatagramChannel:UDP读写 SocketChannel:TCP读写 ServerSocketChannel 支持scatter/gather(分散和聚集) 分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中.因此,Channel将从Channel

Java-NIO(四):通道(Channel)的原理与获取

通道(Channel): 由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互.通道主要用于传输数据,从缓冲区的一侧传到另一侧的实体(如文件.套接字...),反之亦然:通道是访问IO服务的导管,通过通道,我们可以以最小的开销来访问操作系统的I/O服务:顺便说下,缓冲区是通道内部发送数据和接收数据的端点. 在标准的IO当中,都是基于字节流/字符流进

【Flume】flume中通道channel的简单分析梳理

Channels are the repositories where the events are staged on a agent. Source adds the events and Sink removes it. 通道就是事件暂存的地方,source负责往通道中添加event,sink负责从通道中移出event flume1.5.2内置的通道有:内存,文件,jdbc 1.内存通道memory-channel 时间存储在内存队列中,对于性能要求高且能接受agent失败时数据丢失的情况

通道(Channel)的原理与获取

通道(Channel):由 java.nio.channels 包定义 的.Channel 表示 IO 源与目标打开的连接. Channel 类似于传统的“流”.只不过 Channel 本身不能直接访问数据,Channel 只能与 Buffer 进行交互 TestChannel package com.aff.nio; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.File

通道Channel获取四种方法

package com.hp.buffer; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChann

[golang] channel通道

说明 channel是go当中的一个核心类型,可以看做是管道.并发核心单元可以通过channel进行数据的发送和接收,从而实现通信. 在go中,channel是一种数据类型,主要被用来解决协程的同步问题以及协程之间数据共享(数据传递)的问题. go当中的goroutine运行在相同的地址空间,因此访问共享内存地址必须做好同步,goroutine奉行通过通信来共享内存,而不是共享内存来通信. 引用类型channel可用于多个goroutine通讯,在其内部实现了同步,确保并发安全. 定义chann