java基础·杂(NIO之ByteBuffer)

接触了NIO的东西,这里记下,方便以后查阅。

1,NIO

Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。

Channels and Buffers(通道和缓冲区)

    标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读到缓冲区中,或者从缓冲区写入到通道中。

Java NIO的通道类似流,但又有些不同:

    既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。

    通道可以异步地读写。

    通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

Channel的实现:
   FileChannel 从文件中读写数据。-常用
   DatagramChannel 能通过UDP读写网络中的数据。
   SocketChannel 能通过TCP读写网络中的数据。-常用

  ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

2,案例

例如:

Channels and Buffers的例子:
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");//参数 mode 的值可选 "r":可读,"w" :可写,"rw":可读性;
FileChannel inChannel = aFile.getChannel();//返回与此文件关联的唯一 FileChannel 对象。
ByteBuffer buf = ByteBuffer.allocate(48);//create buffer with capacity of 48 bytes
int bytesRead = inChannel.read(buf); //read into buffer.将字节序列从此通道读入给定的缓冲区。读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1
while (bytesRead != -1) {
  buf.flip();  //make buffer ready for read
  while(buf.hasRemaining()){//告知在当前位置和限制之间是否有元素。当且仅当此缓冲区中至少还有一个元素时返回 true
      System.out.print((char) buf.get()); // read 1 byte at a time.相对 get 方法。读取此缓冲区当前位置的字节,然后该位置递增。返回:缓冲区当前位置的字节
  }
  buf.clear(); //make buffer ready for writing
  bytesRead = inChannel.read(buf);
}
aFile.close();

通道可以由FileInputStream,FileOutputStream,RandomAccessFile三个类来产生,例如:FileChannel fc = new FileInputStream().getChannel();与通道交互的一般方式就是使用缓冲器,可以把通道比如为煤矿(数据区),而把缓冲器比如为运煤车,想要得到煤一般都通过运煤车来获取,而不是直接和煤矿取煤。

3,Buffer

在NIO中,数据的读写操作始终是与缓冲区相关联的,读取时,信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区。缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型。ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer。

使用Buffer读写数据一般遵循以下四个步骤:
1,写入数据到Buffer
2,调用flip()方法,反转缓冲区,将Buffer从写模式切换到读模式
3,从Buffer中读取数据
4,调用clear()方法或者compact()方法。clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据,任何未读的数据都被移到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

为了理解Buffer的工作原理,需要熟悉它的三个属性:

capacity,position,limit

position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。

capacity

作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

position
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。

当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据。

创建ByteBuffer

使用allocate()静态方法
    ByteBuffer buffer=ByteBuffer.allocate(256);

    以上方法将创建一个容量为256字节的ByteBuffer,如果发现创建的缓冲区容量太小,唯一的选择就是重新创建一个大小合适的缓冲区。

通过包装一个已有的数组来创建
    如下,通过包装的方法创建的缓冲区保留了被包装数组内保存的数据.

    ByteBuffer buffer=ByteBuffer.wrap(byteArray);

    如果要将一个字符串存入ByteBuffer,可以如下操作:
    String sendString="你好,服务器. ";

    ByteBuffer sendBuffer=ByteBuffer.wrap(sendString.getBytes("UTF-16"));



猜你喜欢

转载自blog.csdn.net/gcc_java/article/details/80568135