一、通道(Channel):
用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。
二、通道的主要实现类
java.nio.channels.Channel 接口:
|--
FileChannel:用于读取、写入、映射和操作文件的通道。
|--
SocketChannel:通过 UDP 读写网络中的数据通道。
|--
ServerSocketChannel:通过 TCP 读写网络中的数据。
|--
DatagramChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。
三、获取通道
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()
五、分散(Scatter)与聚集(Gather)
分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中
六、字符集:Charset
编码:字符串 -> 字节数组
解码:字节数组 -> 字符串
支持通道的类 getChannel() 方法
//非直接缓冲区,通道完成对文件的复制
@Test
public void test01() throws Exception{
FileInputStream in=new FileInputStream("z6.png");
FileOutputStream ou=new FileOutputStream("2.jpg");
//获取通道
FileChannel channeIn = in.getChannel();
FileChannel channelOu = ou.getChannel();
//分配指定大小缓冲区
ByteBuffer allocate = ByteBuffer.allocate(1024);
//将通道中的数据读入缓冲区
while(channeIn.read(allocate)!=-1){
//切换读取数据模式
allocate.flip();
//将缓冲区数据写入通道
channelOu.write(allocate);
//清楚缓冲区
allocate.clear();
}
channeIn.close();
channelOu.close();
in.close();
ou.close();
}
静态方法 open()
//使用直接缓冲区完成文件的复制(内存映射文件)
@Test
public void test02() throws IOException{
FileChannel read = FileChannel.open(Paths.get("z6.png"), StandardOpenOption.READ);
//StandardOpenOption.CREATE_NEW如果不存在则报错,不进行覆盖,create如果存在则进行覆盖
//Path path = Paths.get("e:/", "/s","/s"); 可以进行路径的拼接
FileChannel write = FileChannel.open(Paths.get("2.png"),
StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
//内存映射文件
MappedByteBuffer mapR = read.map(MapMode.READ_ONLY, 0, read.size());
MappedByteBuffer mapW = write.map(MapMode.READ_WRITE, 0, read.size());
byte[] dst=new byte[mapR.limit()];
//直接对缓冲区进行数据的读写操作-因是直接缓冲区可以直接操作,不借用通道
mapR.get(dst);
mapW.put(dst);
read.close();
write.close();
}
缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区 。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的机 本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好
处时分配它们。
通道之间的数据传输
//通道之间的数据传输,直接缓冲区
@Test
public void test03() throws Exception{
FileChannel read = FileChannel.open(Paths.get("z6.png"), StandardOpenOption.READ);
FileChannel write = FileChannel.open(Paths.get("7.png"),
StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
//read.transferTo(0, read.size(), write);
write.transferFrom(read, 0, read.size());
read.close();
write.close();
}
分散(Scatter)与聚集(Gather)
@Test
public void test04() throws IOException{
RandomAccessFile read=new RandomAccessFile("1.txt", "rw");//rw为读写操作简写
FileChannel channel = read.getChannel();//获取通道
ByteBuffer allocate1 = ByteBuffer.allocate(100);//分配缓冲区
ByteBuffer allocate2 = ByteBuffer.allocate(10000);
ByteBuffer dsts[]={allocate1,allocate2};
channel.read(dsts);
System.out.println(new String(dsts[0].array(), 0, dsts[0].limit()));
System.out.println("==================");
System.out.println(new String(dsts[1].array(), 0, dsts[1].limit()));
//以上得出结论在写入缓冲区的时候 ,是有序的,按顺序操作
//写入
for (ByteBuffer byteBuffer : dsts) {
byteBuffer.flip();
}
RandomAccessFile write=new RandomAccessFile("2.txt", "rw");
FileChannel channel2 = write.getChannel();
channel2.write(dsts);
channel2.close();
channel.close();
write.close();
read.close();
}
字符集:Charset
@Test
public void test05() throws IOException{
//nio 支持的编码
/*SortedMap<String,Charset> availableCharsets = Charset.availableCharsets();
Set<Entry<String,Charset>> entrySet = availableCharsets.entrySet();
for (Entry<String, Charset> entry : entrySet) {
System.out.println(entry.getKey()+"=="+entry.getValue());
}*/
Charset cs = Charset.forName("GBK");
CharsetEncoder newEncoder = cs.newEncoder();//编码
CharsetDecoder newDecoder = cs.newDecoder(); //解码
CharBuffer cBuf = CharBuffer.allocate(1024);
cBuf.put("我是中国人");
cBuf.flip();
ByteBuffer bBuf = newEncoder.encode(cBuf);//编码
for (int i = 0; i < bBuf.limit(); i++) {
System.out.println(bBuf.get());
}
bBuf.flip();
CharBuffer decode = newDecoder.decode(bBuf); //解码
System.out.println("=========");
System.out.println(decode.toString());
}