技术探索之旅-NIO学习(四)-通道和字符集

通道

通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
在NIO中,提供了多种通道对象,而所有的通道对象都实现了Channel接口。它们之间的继承关系如下图所示:
这里写图片描述

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

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

•DatagramChannel:通过 UDP 读写网络中的数据通道。

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

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

获取通道的一种方式是对支持通道的对象调用
getChannel() 方法。支持通道的类如下:
 FileInputStream
 FileOutputStream
 RandomAccessFile
 DatagramSocket
 Socket
 ServerSocket
获取通道的其他方式是使用 Files 类的静态方法 newByteChannel() 获
取字节通道。或者通过通道的静态方法 open() 打开并返回指定通道。

FileChannel的常用方法
这里写图片描述
分散和聚集
分散读取(Scattering Reads)是指从Channel 中读取的数据“分散”到多个Buffer 中。
这里写图片描述
注意:按照缓冲区的顺序,从 Channel 中读取的数据依次将 Buffer 填满。

聚集写入(Gathering Writes)是指将多个Buffer 中的数据“聚集”到Channel。
这里写图片描述
注意:按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。

下面为实例程序:

package com.test.nio;

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.Set;

/**
 * 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO中负责缓冲
 *      区中数据的传输。Channel本身不存储数据,因此需要配合缓冲区进行传输
 * 二、通道的主要实现类
 *  java.nio.channels.Channel 接口:
 *    |--FileChannel
 *    |--SocketChannel
 *    |--ServerSocketChannel
 *    |--DatagramChannel
 * 三:获取通道
 * 1.Java 针对支持通道的类提供了getChannel()方法
 * 本地 IO:
 * FileInputStream/FileOutputStream
 * RandomAccessFile
 *
 * 网络 IO
 * Socket
 * ServerSocket
 * DatagramSocket
 * 2.在JDK 1.7 中的NIO.2针对各个通道提供了静态方法 open()
 * 3.在JDK 1.7 中的NIO.2的Files工具类的newByteChannel()
 * 四:通道之间的数据传输
 * transferFrom()
 * transferTo()
 *
 * 五:分散(Scattrer)与聚集(Gather)
 * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
 * 聚集写入(Gathering Writers):将多个缓冲区中的数据聚集到同道中
 *
 * 六:字符集:Charset
 * 编码(encode):字符串->字节数组
 * 解码(decode):字节数组-字符串
 *
 */
public class TestChannel {
    @Test
    public void test7()throws Exception{
        Charset cs1=Charset.forName("GBK");
        //获取编码器
        CharsetEncoder ce=cs1.newEncoder();
        //获取解码器
        CharsetDecoder cd=cs1.newDecoder();

        CharBuffer charBuffer=CharBuffer.allocate(1024);
        charBuffer.put("今天天气不错");
        charBuffer.flip();
        //编码
        ByteBuffer buffer1=ce.encode(charBuffer);
        for(int i=0;i<buffer1.limit();i++){
            System.out.println(buffer1.get());
        }
        //解码
        buffer1.flip();
        CharBuffer buffer2=cd.decode(buffer1);
        System.out.println(buffer2.toString());

        System.out.println("-------------------------");
        buffer1.flip();
        Charset cs2=Charset.forName("UTF-8");
        CharBuffer buffer3=cs2.decode(buffer1);
        System.out.println(buffer3.toString());
    }
    //查看Java支持的字符集
    @Test
    public void test6(){
        Map<String,Charset> map=Charset.availableCharsets();
        Set<Map.Entry<String,Charset>> set=map.entrySet();
        for(Map.Entry<String,Charset> entry:set){
            System.out.println(entry.getKey()+"="+entry.getValue());
        }
    }

    //分散和聚集
    @Test
    public void test5()throws Exception{
        RandomAccessFile raf1=new RandomAccessFile("e:\\122.txt","rw");
        //1.获取通道
        FileChannel channel1=raf1.getChannel();
        //2.分配制定大小的缓冲区
        ByteBuffer buffer1=ByteBuffer.allocate(100);
        ByteBuffer buffer2=ByteBuffer.allocate(1024);
        //3.分散读取
        ByteBuffer[] buffers={buffer1,buffer2};
        channel1.read(buffers);
        for(ByteBuffer buffer:buffers){
            buffer.flip();
        }
        System.out.println(new String(buffers[0].array(),0,buffers[0].limit()));
        System.out.println("-------------------------");
        System.out.println(new String(buffers[1].array(),0,buffers[1].limit()));
        //4.聚集写入
        RandomAccessFile raf2=new RandomAccessFile("e:\\123.txt","rw");
        FileChannel channel2=raf2.getChannel();
        channel2.write(buffers);
    }
    //通道直接的数据传输(直接缓冲区)
    @Test
    public void test4() throws Exception{
        //只读模式
        FileChannel inChannel=FileChannel.open(Paths.get("e:\\122.txt"), StandardOpenOption.READ);
        //读写模式 StandardOpenOption.CREATE 当目标文件不存在时  创建一个新文件 CREATE_NEW则文件已存在时 会报异常
        FileChannel outChannel=FileChannel.open(Paths.get("e:\\123.txt"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
        inChannel.transferTo(0,inChannel.size(),outChannel);
        //下面的方法与上面效果相同
        //outChannel.transferFrom(inChannal,0,inChannal.size());

        inChannel.close();
        outChannel.close();
    }
    //使用直接缓冲区完成文件的复制(内存映射文件)
    @Test
    public void test3()throws Exception{
        //只读模式
        FileChannel inChannel=FileChannel.open(Paths.get("e:\\122.txt"), StandardOpenOption.READ);
        //读写模式 StandardOpenOption.CREATE 当目标文件不存在时  创建一个新文件 CREATE_NEW则文件已存在时 会报异常
        FileChannel outChannel=FileChannel.open(Paths.get("e:\\123.txt"),StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
        //内存映射文件
        MappedByteBuffer inMappedBuf=inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
        MappedByteBuffer outMappedBuf=outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
        byte[] dst=new byte[inMappedBuf.limit()];
        //将缓冲区中是的数据读入到数组
        inMappedBuf.get(dst);
        //将数组中的数据放入缓冲区
        outMappedBuf.put(dst);
        inChannel.close();
        outChannel.close();

    }
    //利用通道完成文件的复制(非直接缓冲区)
    @Test
    public  void test2()throws Exception{
        FileInputStream fin=new FileInputStream("e:\\122.txt");
        FileOutputStream fos=new FileOutputStream("e:\\123.txt");
        //1.获取通道
        FileChannel inChannel=fin.getChannel();
        FileChannel outChannel=fos.getChannel();
        inChannel.transferTo(0,inChannel.size(),outChannel);
        //2.分配制定大小的缓冲区
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        //3.将通道中的数据存入缓冲区中
        while (inChannel.read(buffer)!=-1){
            //4.切换到读数据模式
            buffer.flip();
            //5.将缓冲区中的数据写入通道中
            outChannel.write(buffer);
            //6.清空缓冲区
            buffer.clear();
        }
        outChannel.close();
        inChannel.close();
        fos.close();
        fin.close();
    }
    //利用通道读取数据
    @Test
    public void test1()throws Exception{
        FileInputStream fin=new FileInputStream(new File("e:\\122.txt"));
        //获取通道
        FileChannel fc=fin.getChannel();
        //创建缓冲区
        ByteBuffer buffer=ByteBuffer.allocate(1024);
        //读取数据到缓冲区
        fc.read(buffer);
        buffer.flip();
        while (buffer.remaining()>0){
            byte b=buffer.get();
            System.out.println((char)b);
        }
        //剩余可操作的数量
       /* while (fc.read(buffer)!=-1){
            byte b=buffer.get();
            System.out.println((char)b);
        }*/
        fc.close();
        fin.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值