趣文网 > 作文大全

程序员:JAVA NIO系列之通道(Channel)

2020-12-02 03:45:01
相关推荐

1. 通道(Channel)

通道(Channel):由java.nio.Channels包定义的。Channel表示IO源与目标打开的连接。Channel类似于传统中的“流”,只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互。

Channel在java NIO中负责缓冲区的数据传输。Channel本身不存在数据,因此需要配合缓冲区进行传输。

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

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

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

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

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

FileChannel常用方法

2. 获取通道

有三种获取通道的方式:

对支持通道的对象调用getChannel()方法。

支持通道的类如下:

FileInputStream

FileOutputStream

RandomAccessFile

DatagramSocket

Socket

ServerSocket

使用Files类的静态方法newByteChannel()获取字节通道(NIO2)

通过通道的静态方法 open() 打开并返回指定通道(NIO2)

将 Buffer 中数据写入 Channel: write()

从 Channel 读取数据到 Buffer: read()

3. 通道的数据传输

利用通道实现文件的复制(非直接缓冲区)

public static void copyFile() {

long start = System.currentTimeMillis();

FileChannel outChannel = null;

FileChannel inChannel = null;

FileInputStream fis = null;

FileOutputStream fos = null;

try {

fis = new FileInputStream("E:demoJava网络编程(第4版).pdf");

fos = new FileOutputStream("E:demoJava网络编程(第4版copy).pdf");

//1. 获取通道

inChannel = fis.getChannel();

outChannel = fos.getChannel();

//分配指定大小的缓冲区

ByteBuffer buf = ByteBuffer.allocate(1024);

//将通道中的数据存入缓冲区

while (inChannel.read(buf) != -1) {

//切换到读取数据模式

buf.flip();

//将缓冲区的数据写入通道中

outChannel.write(buf);

//清空缓冲区

buf.clear();

}

} catch (Exception 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(fis != null){

try {

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if(fos != null){

try {

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

System.out.println("耗费时间:"+(System.currentTimeMillis() - start));

}

使用直接缓冲区实现文件的复制(内存映射文件)

public static void copyFileByChannel(){

long start = System.currentTimeMillis();

try {

//获取通道

FileChannel inChannel = FileChannel.open(Paths.get("e:demoJava网络编程(第4版).pdf"), StandardOpenOption.READ);

FileChannel outChannel = FileChannel.open(Paths.get("e:demoJava网络编程(第4版copy).pdf"),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();

} catch (IOException e) {

e.printStackTrace();

}

System.out.println("耗费时间:"+(System.currentTimeMillis() - start));

}

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

public static void transfer(){

long start = System.currentTimeMillis();

try {

FileChannel inChannel = FileChannel.open(Paths.get("e:demoJava网络编程(第4版).pdf"),StandardOpenOption.READ);

FileChannel outChannel = FileChannel.open(Paths.get("e:demoJava网络编程(copy).pdf"),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

inChannel.transferTo(0,inChannel.size(),outChannel);

inChannel.close();

outChannel.close();

} catch (IOException e) {

e.printStackTrace();

}

System.out.println("耗费时间:"+(System.currentTimeMillis() - start));

}

从效率上来看,第三种最快,第一种最慢

4. 零拷贝

public abstract long transferTo(long position, long count, WritableByteChannel target) 将当前channel的数据拷贝到target所指的channel

public abstract long transferFrom(ReadableByteChannel src,long position, long count) 将src所指的channel的数据拷贝到当前channel

5. 分散读取与聚集写入

分散读取(Scattering Reads)是指从Channel中读取的数据“分散”到多个 Buffer 中

聚集写入(Gathering Writes)是指将多个 Buffer 中的数据“聚集”

到 Channel。

注意:分散读取时按照缓冲区的顺序,从 Channel 中读取的数据依次将Buffer填满。聚集写入时按照缓冲区的顺序,写入 position 和 limit 之间的数据到 Channel 。

分散读取和聚集写入示例

/**

* 分散读取和聚集写入

*/

public static void randomAccess(){

try {

RandomAccessFile fromFile = new RandomAccessFile("e:demo est.txt","rw");

// 1. 获取通道

FileChannel inChannel = fromFile.getChannel();

//2、分配指定大小的缓冲区

ByteBuffer buf1 = ByteBuffer.allocate(512);

ByteBuffer buf2 = ByteBuffer.allocate(10240);

//分散读取

ByteBuffer[] bufs = {buf1,buf2};

inChannel.read(bufs);

for(ByteBuffer byteBuffer : bufs){

byteBuffer.flip();

}

System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));

System.out.println("----------------");

System.out.println(new String(bufs[1].array(),0,bufs[1].limit()));

//聚集写入

RandomAccessFile toFrom = new RandomAccessFile("e:demo estCopy.txt","rw");

FileChannel outChannel = toFrom.getChannel();

outChannel.write(bufs);

} catch (Exception e) {

e.printStackTrace();

}

}

6. 编解码

public static void charset() throws Exception{

//查看支持的字符集列表

// Map map = Charset.availableCharsets();

// for(Map.Entry entry : map.entrySet()){

// System.out.println(entry.getKey()+"="+entry.getValue());

// }

//指定编码集

Charset c = Charset.forName("GBK");

//获取编码器

CharsetEncoder ce = c.newEncoder();

//获取解码器

CharsetDecoder cd = c.newDecoder();

CharBuffer cuf = CharBuffer.allocate(1024);

cuf.put("好好学习,天天向上");

cuf.flip();

//编码

ByteBuffer buffer = ce.encode(cuf);

for(int i = 0;i < 18; i++){

System.out.println(buffer.get());

}

//解码

buffer.flip();

CharBuffer charBuffer = cd.decode(buffer);

System.out.println(charBuffer.toString());

System.out.println("--------------------------------");

Charset cs2 = Charset.forName("UTF-8");

buffer.flip();

CharBuffer charBuffer1 = cs2.decode(buffer);

System.out.println(charBuffer1.toString());

}

阅读剩余内容
网友评论
显示评论内容(2) 收起评论内容
  1. 2021-09-14 21:42一辈子幸福[湖北省网友]IP:3662290216
    学习JAVA和NIO学定不能错过这个系列通道(Channel)讲解非常透彻让我受益匪浅!
    顶22踩0
  2. 2020-05-26 18:44我爱你,与青春有关的日子[广东省网友]IP:1732234233
    这个系列对程序员真太有帮助了讲解清晰示例也很实用期待更多教程!
    顶0踩0
相关内容
延伸阅读
小编推荐

大家都在看

英语四六级作文万能模板 我的家风家训作文600字 外国人写的中文作文 把快乐分享给别人作文 礼赞新中国作文 同学自画像作文 我的烦恼写一篇作文 小学英语作文六年级 我的理想作文500字老师 我是一个听话的孩子作文400字 豆芽长成记作文 碎片化阅读作文 秋天作文600字写景 过年作文结尾 勇气让我走出困境作文 祖国在我心中作文800字 盼望长大的作文 有关司马迁的作文素材 身边人的作文 赞扬学校的作文 高考二卷作文题目 八公山豆腐作文 家乡的变化作文三百字 描写火车站的作文 庆祝建国70周年作文 令我感动的一个人作文 我的遗憾作文600字 城市和农村的区别作文 mytravelplan作文 美为主题的作文