1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.RandomAccessFile; 5 import java.nio.ByteBuffer; 6 import java.nio.CharBuffer; 7 import java.nio.MappedByteBuffer; 8 import java.nio.channels.FileChannel; 9 import java.nio.channels.FileChannel.MapMode; 10 import java.nio.charset.CharacterCodingException; 11 import java.nio.charset.Charset; 12 import java.nio.charset.CharsetDecoder; 13 import java.nio.charset.CharsetEncoder; 14 import java.nio.file.Paths; 15 import java.nio.file.StandardOpenOption; 16 import java.util.Map; 17 import java.util.Map.Entry; 18 import java.util.Set; 19 20 import org.junit.Test; 21 22 /* 23 * 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。 24 * 25 * 二、通道的主要实现类 26 * java.nio.channels.Channel 接口: 27 * |--FileChannel 28 * |--SocketChannel 29 * |--ServerSocketChannel 30 * |--DatagramChannel 31 * 32 * 三、获取通道 33 * 1. Java 针对支持通道的类提供了 getChannel() 方法 34 * 本地 IO: 35 * FileInputStream/FileOutputStream 36 * RandomAccessFile 37 * 38 * 网络IO: 39 * Socket 40 * ServerSocket 41 * DatagramSocket 42 * 43 * 2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open() 44 * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel() 45 * 46 * 四、通道之间的数据传输 47 * transferFrom() 48 * transferTo() 49 * 50 * 五、分散(Scatter)与聚集(Gather) 51 * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中 52 * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中 53 * 54 * 六、字符集:Charset 55 * 编码:字符串 -> 字节数组 56 * 解码:字节数组 -> 字符串 57 * 58 */ 59 public class TestChannel { 60 61 //字符集 62 @Test 63 public void test6() throws IOException{ 64 Charset cs1 = Charset.forName("GBK"); 65 66 //获取编码器 67 CharsetEncoder ce = cs1.newEncoder(); 68 69 //获取解码器 70 CharsetDecoder cd = cs1.newDecoder(); 71 72 CharBuffer cBuf = CharBuffer.allocate(1024); 73 cBuf.put("好好学习天天向上!"); 74 cBuf.flip(); 75 76 //编码 77 ByteBuffer bBuf = ce.encode(cBuf); 78 79 for (int i = 0; i < 12; i++) { 80 System.out.println(bBuf.get()); 81 } 82 83 //解码 84 bBuf.flip(); 85 CharBuffer cBuf2 = cd.decode(bBuf); 86 System.out.println(cBuf2.toString()); 87 88 System.out.println("------------------------------------------------------"); 89 90 Charset cs2 = Charset.forName("GBK"); 91 bBuf.flip(); 92 CharBuffer cBuf3 = cs2.decode(bBuf); 93 System.out.println(cBuf3.toString()); 94 } 95 96 @Test 97 public void test5(){ 98 Mapmap = Charset.availableCharsets(); 99 100 Set > set = map.entrySet();101 102 for (Entry entry : set) {103 System.out.println(entry.getKey() + "=" + entry.getValue());104 }105 }106 107 //分散和聚集108 @Test109 public void test4() throws IOException{110 RandomAccessFile raf1 = new RandomAccessFile("1.txt", "rw");111 112 //1. 获取通道113 FileChannel channel1 = raf1.getChannel();114 115 //2. 分配指定大小的缓冲区116 ByteBuffer buf1 = ByteBuffer.allocate(100);117 ByteBuffer buf2 = ByteBuffer.allocate(1024);118 119 //3. 分散读取120 ByteBuffer[] bufs = {buf1, buf2};121 channel1.read(bufs);122 123 for (ByteBuffer byteBuffer : bufs) {124 byteBuffer.flip();125 }126 127 System.out.println(new String(bufs[0].array(), 0, bufs[0].limit()));128 System.out.println("-----------------");129 System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));130 131 //4. 聚集写入132 RandomAccessFile raf2 = new RandomAccessFile("2.txt", "rw");133 FileChannel channel2 = raf2.getChannel();134 135 channel2.write(bufs);136 }137 138 //通道之间的数据传输(直接缓冲区)139 @Test140 public void test3() throws IOException{141 FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);142 FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);143 144 // inChannel.transferTo(0, inChannel.size(), outChannel);145 outChannel.transferFrom(inChannel, 0, inChannel.size());146 147 inChannel.close();148 outChannel.close();149 }150 151 //使用直接缓冲区完成文件的复制(内存映射文件)152 @Test153 public void test2() throws IOException{ //2127-1902-1777154 long start = System.currentTimeMillis();155 156 FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);157 FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);158 159 //内存映射文件160 MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());161 MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());162 163 //直接对缓冲区进行数据的读写操作164 byte[] dst = new byte[inMappedBuf.limit()];165 inMappedBuf.get(dst);166 outMappedBuf.put(dst);167 168 inChannel.close();169 outChannel.close();170 171 long end = System.currentTimeMillis();172 System.out.println("耗费时间为:" + (end - start));173 }174 175 //利用通道完成文件的复制(非直接缓冲区)176 @Test177 public void test1(){ //10874-10953178 long start = System.currentTimeMillis();179 180 FileInputStream fis = null;181 FileOutputStream fos = null;182 //①获取通道183 FileChannel inChannel = null;184 FileChannel outChannel = null;185 try {186 fis = new FileInputStream("d:/1.mkv");187 fos = new FileOutputStream("d:/2.mkv");188 189 inChannel = fis.getChannel();190 outChannel = fos.getChannel();191 192 //②分配指定大小的缓冲区193 ByteBuffer buf = ByteBuffer.allocate(1024);194 195 //③将通道中的数据存入缓冲区中196 while(inChannel.read(buf) != -1){197 buf.flip(); //切换读取数据的模式198 //④将缓冲区中的数据写入通道中199 outChannel.write(buf);200 buf.clear(); //清空缓冲区201 }202 } catch (IOException e) {203 e.printStackTrace();204 } finally {205 if(outChannel != null){206 try {207 outChannel.close();208 } catch (IOException e) {209 e.printStackTrace();210 }211 }212 213 if(inChannel != null){214 try {215 inChannel.close();216 } catch (IOException e) {217 e.printStackTrace();218 }219 }220 221 if(fos != null){222 try {223 fos.close();224 } catch (IOException e) {225 e.printStackTrace();226 }227 }228 229 if(fis != null){230 try {231 fis.close();232 } catch (IOException e) {233 e.printStackTrace();234 }235 }236 }237 238 long end = System.currentTimeMillis();239 System.out.println("耗费时间为:" + (end - start));240 241 }242 243 }