Java NIO学习系列二:Channel

  上文总结了Java NIO中的Buffer相关知识点,本文中我们来总结一下它的好兄弟:Channel。上文有说到,Java NIO中的Buffer一般和Channel配对使用,NIO中的所有IO都起始于一个Channel,一个Channel就相当于一个流,,可以从Channel中读取数据到Buffer,或者写数据到Channel中。

Channel简介

FileChannel

SocketChannel

ServerSocketChannel

DatagramChannel

1. Channel简介

  Java NIO中的Channel类似流,但是有一些不同:

  • Channel既可以支持写也可以支持读,而流则是单向的,只能支持写或者读;
  • Channel支持异步读写;
  • Channel一般和Buffer配套使用,从Channel中读取数据到Buffer中,或从Buffer写入到Channel中;

  Channel的主要实现类有如下几种:

  • FileChannel,可以对文件读/写数据;
  • DatagramChannel,通过UDP从网络读/写数据;
  • SocketChannel,通过TCP从网络读/写数据;
  • ServerSocketChannel,允许你监听TCP连接,对于每个TCP连接都创建一个SocketChannel;

2. FileChannel

  Java NIO FileChannel是一类文件相连的channel,通过它可以从文件读取数据,或向文件写数据。FileChannel类是Java NIO类库提供的用于代替标准Java IO API来读写文件。FileChannel不能设置为非阻塞模式,只能工作在阻塞模式下。

2.1 打开FileChannel

  在使用FileChannel之前先要打开它,就I/O类库中有三个类被修改了,用以产生FileChannel,这三个类是:InputStream、OutputStream、RandomAccessFile,如下是如何从RandomAccessFile获取FileChannel:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

2.2 从FileChannel读取数据

  首先需要分配一个Buffer,从FileChannel读取的数据会读到Buffer中(是不是有点绕)。然后调用FileChannel的read()方法来读数据,这个方法会把数据读到Buffer中,返回的int代表读取了多少字节,返回-1代表文件末尾。

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

2.3 往FileChannel写数据

  通过调用FileChannel的write()方法可以往其中写数据,参数是一个Buffer:

String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
while(buf.hasRemaining()) {
    channel.write(buf);
}

  这里write()方法也没有保证一次写入多少数据,我们只是不断重复直到写完。

2.4 关闭FileChannel

  用完FileChannel之后记得要将其关闭:

channel.close();

2.5 FileChannel位置

  调用FileChannel对象的position()方法可以获取其position,也可以调用position(long pos)设置其position:

// 获取position
long pos channel.position();
// 设置position
channel.position(pos +123);

  如果将position设置到文件末尾后面,然后尝试读取文件,会返回-1;

  如果将position设置到文件末尾后面,然后尝试向文件中写数据,则文件会自动扩展,并且从设置的position位置处开始写数据,这会导致“file hole”,即物理文件会有间隙。

2.6 FileChannel尺寸

  size()方法返回filechannel连接的文件的尺寸大小:

long fileSize = channel.size(); 

2.7 截短FileChannel

  truncate()方法可以截短文件:

channel.truncate(1024);

  如上,将文件截取为1024字节长度。

2.8 FileChannel Force

  FileChannel.force()方法会刷新所有未写入到磁盘的数据到磁盘上。因为操作系统会先将数据缓存到内存中,再一次性写入磁盘,所以不能保证写到channel中的数据是否写入到磁盘上,所以可以调用flush()方法强制将数据写入磁盘。

  force()方法有一个boolean参数,代表是否要写入文件的元数据(比如权限):

channel.force(true);

3. SocketChannel

  Java NIO SocketChannel用于和TCP网络socket相连,等同于Java网络包中的Socket。可以通过两种方式来创建一个SocketChannel:

  • 打开一个SocketChannel并且将其和网络上的某台服务器相连;
  • 当有一个连接到达一个ServerSocketChannel时会自动创建一个SocketChannel;

3.1 打开Socket通道

  如下示例说明了如何打开一个SocketChannel:

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

3.2 关闭Socket通道

  对于这种资源类的使用,是要记得及时关闭的:

socketChannel.close();

3.3 Reading from a SocketChannel

  调用read()方法可以读取数据:

4. ServerSocketChannel

5. DatagramChannel

猜你喜欢

转载自www.cnblogs.com/volcano-liu/p/11066883.html