通道(Channel)是NIO用来传输数据的。和流类似,只不过有很大的区别
区别:
类名 | 作用 |
---|---|
FileChannel | 用于文件的数据读写 |
DatagramChannel | 用于UDP的数据读写 |
ServerSocketChannel和SocketChannel | 用于TCP的数据读写 |
package com.dashu.nio;
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.CharacterCodingException;
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;
/**
* 在NIO中,缓冲区就像高铁,通道就是高铁路,人就是数据。
* 人坐高铁,高铁通过高铁路从贵阳到北京
* 缓冲区存数据,通道传输缓冲区
*
* 一、通道(Channel)
* 用于源节点与目标节点的连接。
* 在Java NIO中负责缓冲区中数据的传输
* Channel本身不存储数据,因此需要配合缓冲区进行传输
*
* 二、通道的主要实现类
* java.nio.channels.Channel接口
* |--FileChannel
* |--SocketChannel
* |--ServerSocketChannel
* |--DatagramChannel
*
* 三、获取通道
* 1、Java针对支持通道的类提供了getChannel()方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
*
* 网络IO:
* Socket
* ServerSocket
* DatagramSocket
*
* 2、在JDK1.7中的NIO.2针对各个通道提供了静态方法open()
* 3、在JDK1.7中的NIO.2的Feles工具类的newByteChannel()
*
* 四、通道之间的数据传输
* transferFrom()
* transferTo()
*
* 五、分散(Scatter)与聚集(Gather)
* 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
* 聚集写入(Gathering Writes):将多个缓冲去中的数据聚集到通道中
*
* 六、字符集:Charset
* 编码:字符串 -> 字节数组
* 解码:字节数组 -> 字符串
*/
public class NioChannel {
public static void main(String[] args) throws CharacterCodingException {
NioChannel nioChannel = new NioChannel();
}
/**
* 分散读取,和聚集写入
*/
public void test04() {
//输入文件
RandomAccessFile inRandomAccessFile = null;
//输入文件通道
FileChannel inFileChannel = null;
//输出通道
RandomAccessFile outRandomAccessFile = null;
//输出文件通道
FileChannel outFileChannel = null;
try {
//创建输入文件
inRandomAccessFile = new RandomAccessFile("d:/a.txt", "rw");
//创建输入通道
inFileChannel = inRandomAccessFile.getChannel();
//缓冲区1
ByteBuffer byteBuffer1 = ByteBuffer.allocate(100);
//缓冲区2
ByteBuffer byteBuffer2 = ByteBuffer.allocate(100);
//缓冲区数组
ByteBuffer[] byteBuffers = {byteBuffer1, byteBuffer2};
//将输入通道中的数据写到缓冲区数组
inFileChannel.read(byteBuffers);
//切换缓冲区数组中缓冲区的模式:读
for (ByteBuffer byteBuffer : byteBuffers) {
byteBuffer.flip();
}
//分别打印缓冲区中的数据
System.out.println(new String(byteBuffers[0].array(), 0, byteBuffers[0].limit()));
System.out.println("-----------");
System.out.println(new String(byteBuffers[1].array(), 0, byteBuffers[1].limit()));
//创建输出文件
outRandomAccessFile = new RandomAccessFile("d:/a2.txt", "rw");
//创建输出通道
outFileChannel = outRandomAccessFile.getChannel();
//将缓冲区数组的数据写到输出通道
outFileChannel.write(byteBuffers);
} catch (Exception e) {
e.printStackTrace();
} finally {
//通道和文件输入流关闭关闭
if (outFileChannel != null) {
try {
outFileChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (outRandomAccessFile != null) {
try {
outRandomAccessFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inFileChannel != null) {
try {
inFileChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inRandomAccessFile != null) {
try {
inRandomAccessFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 通道之间的数据传输
*/
public void test03() {
//获取当前时间毫秒
long start = System.currentTimeMillis();
//获取文件输入通道
FileChannel inChannel = null;
//获取文件输出通道
FileChannel outChannel = null;
try {
//创建文件输入通道(StandardOpenOption.READ:读)
inChannel = FileChannel.open(Paths.get(""), StandardOpenOption.READ);
//创建文件输出通道(StandardOpenOption.WRITE:写, StandardOpenOption.READ:读, StandardOpenOption.CREATE:文件不存在创建,文件存在覆盖)
outChannel = FileChannel.open(Paths.get(""), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
//将输入文件通道的输据转移到输出文件通道
inChannel.transferTo(0, inChannel.size(), outChannel);
//将输入文件通道的输据转移到输出文件通道
outChannel.transferFrom(inChannel, 0, inChannel.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
//通道关闭
if (outChannel != null) {
try {
outChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//获取当前时间毫秒
long end = System.currentTimeMillis();
//输出
System.out.println("耗时:" + (end - start));
}
/**
* 利用通道完成文件的复制(直接缓冲区)
*/
public void test02() {
//获取当前时间毫秒
long start = System.currentTimeMillis();
//文件输入通道
FileChannel inChannel = null;
//文件输出通道
FileChannel outChannel = null;
try {
// 输入通道(StandardOpenOption.READ:读)
inChannel = FileChannel.open(Paths.get("d:/a.txt"), StandardOpenOption.READ);
// 输入通道(StandardOpenOption.WRITE:写, StandardOpenOption.READ:读, StandardOpenOption.CREATE:文件不存在创建,文件存在覆盖)
outChannel = FileChannel.open(Paths.get("d:/a3.txt"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
//通过输入通道获取输入Buffer
MappedByteBuffer inMappedByteBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
//通过输出通道获取输出Buffer
MappedByteBuffer outMappedByteBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//创建byte数组
byte[] dst = new byte[inMappedByteBuffer.limit()];
//获取输入Buffer的数据保存到byte数组
inMappedByteBuffer.get(dst);
//将byte数组的数据保存到输出Buffer
outMappedByteBuffer.put(dst);
} catch (Exception e) {
//异常抛出
e.printStackTrace();
} finally {
//通道关闭
if (outChannel != null) {
try {
outChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//获取当前时间毫秒
long end = System.currentTimeMillis();
//输出
System.out.println("耗时:" + (end - start));
}
/**
* 利用通道完成文件的复制(非直接缓冲区)
*/
public void test01() {
//获取当前时间毫秒
long start = System.currentTimeMillis();
//文件输入流
FileInputStream fileInputStream = null;
//文件输出流
FileOutputStream fileOutputStream = null;
//文件输入通道
FileChannel inChannel = null;
//文件输出通道
FileChannel outChannel = null;
try {
//输入文件
fileInputStream = new FileInputStream("d:/a.txt");
//输出文件
fileOutputStream = new FileOutputStream("d:/a2.txt");
//输入通道
inChannel = fileInputStream.getChannel();
//输出通道
outChannel = fileOutputStream.getChannel();
//创建缓存区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//循环将”输入通道“中的数据读取到”缓存区“,然后将”缓存区“中的数据写入到”输出通道“
while (true) {
//先清空缓存区
byteBuffer.clear();
//将”输入通道“中的数据读取(存入)到”缓存区“
int read = inChannel.read(byteBuffer);
//判断”输入通道“中的数据是否读取完,读取完,退出循环
if (read == -1) {
break;
}
//切换”缓存区“模式:读
byteBuffer.flip();
//将”缓存区“中的数据写到(存入)”输出通道“
outChannel.write(byteBuffer);
}
} catch (Exception e) {
//异常抛出
e.printStackTrace();
} finally {
//关闭通道和流
if (outChannel != null) {
try {
outChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//获取当前时间毫秒
long end = System.currentTimeMillis();
//输出
System.out.println("耗时:" + (end - start));
}
}