一、通道(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 }