NIO —— Channel (通道、管道) 学习

一、Channel (通道、管道)

A、通道(Channel)
用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。

B、通道的主要实现类

java.nio.channels.Channel 接口:
	|--FileChannel
	|--SocketChannel
	|--ServerSocketChannel
	|--DatagramChannel

C、通道对象的构造

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

    本地 IO:
    	FileInputStream/FileOutputStream
    	RandomAccessFile
    
    网络IO:
    	Socket
    	ServerSocket
    	DatagramSocket
    
  2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open()
    |–FileChannel.open(path, options)
    |–SocketChannel.open(SocketAddress remote)
    |–ServerSocketChannel.open()
    |–DatagramChannel.open(ProtocolFamily family)

  3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel()

D、通道之间的数据传输
transferFrom()
transferTo()

E、分散(Scatter)与聚集(Gather)
分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中

F、字符集:Charset
编码:字符串 -> 字节数组
解码:字节数组 -> 字符串

二、FileChannel 利用通道完成文件的复制(非直接缓冲区)

①获取通道
②分配指定大小的缓冲区
③将通道中的数据存入缓冲区中
④将缓冲区中的数据写入通道中

//利用通道完成文件的复制(非直接缓冲区)
@Test
public void test1FileChannel(){   //10874-10953
	long start = System.currentTimeMillis();
	
	FileInputStream fis = null;
	FileOutputStream fos = null;
	//①获取通道
	FileChannel inChannel = null;
	FileChannel outChannel = null;
	try {
		fis = new FileInputStream("d:/1.mkv");
		fos = new FileOutputStream("d:/2.mkv");
		
		inChannel = fis.getChannel();
		outChannel = fos.getChannel();
		
		//②分配指定大小的缓冲区
		ByteBuffer buf = ByteBuffer.allocate(1024);
		
		//③将通道中的数据存入缓冲区中
		while(inChannel.read(buf) != -1){
			buf.flip(); //切换读取数据的模式
			//④将缓冲区中的数据写入通道中
			outChannel.write(buf);
			buf.clear(); //清空缓冲区
		}
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		if(outChannel != null){
			try {
				outChannel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if(inChannel != null){
			try {
				inChannel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if(fos != null){
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		if(fis != null){
			try {
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	long end = System.currentTimeMillis();
	System.out.println("耗费时间为:" + (end - start));	
}

三、MappedByteBuffer 使用直接缓冲区完成文件的复制(内存映射文件)

//使用直接缓冲区完成文件的复制(内存映射文件)
@Test
public void test2MappedByteBuffer() throws IOException{//2127-1902-1777
	long start = System.currentTimeMillis();
	
	FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);
	FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
	
	//内存映射文件
	MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
	MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
	
	//直接对缓冲区进行数据的读写操作
	byte[] dst = new byte[inMappedBuf.limit()];
	inMappedBuf.get(dst);
	outMappedBuf.put(dst);
	
	inChannel.close();
	outChannel.close();
	
	long end = System.currentTimeMillis();
	System.out.println("耗费时间为:" + (end - start));
}

四、FileChannel 通道之间的数据传输(直接缓冲区)

  • StandardOpenOption.READ //读访问。
  • StandardOpenOption.WRITE //写访问。
  • StandardOpenOption.CREATE //创建一个新文件,如果不存在。
//通道之间的数据传输(直接缓冲区)	
@Test
public void test3transferFrom() throws IOException{
	FileChannel inChannel = FileChannel.open(Paths.get("d:/1.mkv"), StandardOpenOption.READ);
	FileChannel outChannel = FileChannel.open(Paths.get("d:/2.mkv"), StandardOpenOption.WRITE, 
								StandardOpenOption.READ, StandardOpenOption.CREATE);
	
//  inChannel.transferTo(0, inChannel.size(), outChannel);
	outChannel.transferFrom(inChannel, 0, inChannel.size()); //transferFrom 和 transferTo是相对的
	
	inChannel.close();
	outChannel.close();
}

五、获取所有字符集

/**
 * 获取所有字符集
 */
@Test
public void test5Charset(){
	Map<String, Charset> map = Charset.availableCharsets();
	
	Set<Entry<String, Charset>> set = map.entrySet();
	
	for (Entry<String, Charset> entry : set) {
		System.out.println(entry.getKey() + "=" + entry.getValue());
	}
}

六、编码器、解码器

/**
 * 字符集
 * 编码器、解码器
 * @throws IOException
 */
@Test
public void test6newEncoder() throws IOException{
	Charset cs1 = Charset.forName("GBK");
	
	//获取编码器
	CharsetEncoder ce = cs1.newEncoder();
	
	//获取解码器
	CharsetDecoder cd = cs1.newDecoder();
	
	CharBuffer cBuf = CharBuffer.allocate(1024);
	cBuf.put("尚硅谷威武!");
	cBuf.flip();
	
	//编码
	ByteBuffer bBuf = ce.encode(cBuf);
	
	for (int i = 0; i < 12; i++) {
		System.out.println(bBuf.get());
	}
	
	//解码
	bBuf.flip();
	CharBuffer cBuf2 = cd.decode(bBuf);
	System.out.println(cBuf2.toString());
	System.out.println("------------------------------------------------------");
	
	Charset cs2 = Charset.forName("GBK");
	bBuf.flip();
	CharBuffer cBuf3 = cs2.decode(bBuf);
	System.out.println(cBuf3.toString());
}

猜你喜欢

转载自blog.csdn.net/xiaojin21cen/article/details/87975942