标签 java 下的文章

Buffer是一块将要写到Channel里的数据,或者刚从Channel里读出来的数据。它是用来保存数据的一个对象,并且作为NIO Channel的其中一个端点(另一端可能是网络或者文件等)。Buffer提供了一种访问数据的机制,并且跟踪数据读写流程。

Buffer是Java 老的IO和NIO的主要不同之一。以前老的IO直接从流中读或者写。现在数据是从Buffer中都数据或者将写的数据写入Buffer中。在NIO中,Channel就相当于以前的Stream。了解更多NIO Channel可以访问这里

Buffer特点:

1 Buffer是NIO的基本构建块。
2 提供固定大小的容器来读写数据。
3 每一个Buffer都是可读的,但是选中的Buffer才可以写。
4 Buffer是Channel的其中一个端点。
5 在只读Buffer中数据内容是不可变的,但是Buffer的mark,position,limit是可以变的。
6 默认Buffer不是线程安全的。

Buffer类型:

每一个原生类型都有对应的Buffer类型。所有的Buffer类型都实现了Buffer接口。最常用的Buffer类型是ByteBuffer。在Java NIO包中包含如下的Buffer类型:ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer,MappedByteBuffer。

Buffer Capacity:

Buffer是固定大小的类型。如果Buffer满了,那么必须先clear,然后才能继续写入。一旦Capacity被设置就不能再改。

Buffer Limit:

在写模式中,Buffer的limit和capacity相同。在读模式中,limit是最后写入数据的索引加1。随着Buffer不断写入,Limit会保持增长。0 <= limit >= capacity

Buffer Position:

position指向Buffer的当前位置。当Buffer刚被新建的时候,position指向0,当读或者写的时候,position增加到下一个索引。Position在0和Limit之间。

Buffer Mark:

Mark就像对Buffer中的位置做了一个书签。当调用mark()方法的时候,当前的position会被记录。调用reset()方法可以恢复到之前mark的position。

Buffer flip,clear,rewind:

flip():调用此方法,使得Buffer准备开始读或者开始一系列新的写。设置limit=position,position=0.
clear():调用此方法,使得Buffer准备开始写或者启动一系列的新的读。设置limit=capacity,position=0.
rewind():想要从头开始读时,调用此方法,会把position设成0.

从Buffer中读数据示例代码:

ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byteBuffer.flip(); //Flip the buffer to prepare for read operation.
int numberOfBytes = fileChannel.read(byteBuffer);
char c = (char)byteBuffer.get();

向Buffer中写数据:

ByteBuffer byteBuffer = ByteBuffer.allocate(512);
byteBuffer.put((byte) 0xff);

在NIO中,如果你要向文件中写数据,先把数据写入到Buffer,然后用Channel把Buffer写入到文件。与此同理,如果要从文件读数据,用Channel把数据从文件读到Buffer,然后从Buffer中取数据。

package com.javapapers.java.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class BufferExample {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("temp.txt");
        write(path);
        read(path);
    }

    private static void write(Path path) throws IOException {
        String input = "NIO Buffer Hello World!";
        byte[] inputBytes = input.getBytes();
        ByteBuffer byteBuffer = ByteBuffer.wrap(inputBytes);
        FileChannel channelWrite = FileChannel.open(path,
                StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        channelWrite.write(byteBuffer);
        channelWrite.close();
    }

    private static void read(Path path) throws IOException {
        FileChannel channelRead = FileChannel.open(path);
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        channelRead.read(byteBuffer);
        byte[] byteArray = byteBuffer.array();
        String fileContent = new String(byteArray).trim();
        System.out.println("File Content: " + fileContent);
        channelRead.close();
    }
}

本文翻译自 javapapers文章,仅供参考和学习。

在Java NIO中,Channel被用来I/O传输。Channel就像一个用来在Buffer和另外一头的实体(比如文件)之间传输数据的管道。一个Channel从一个实体里读取数据,并且把数据放到缓冲区(Buffer)里供别人(一般是我们的程序)消费,类似的,我们应该把数据写入到缓冲区里,然后Channel会把缓冲区里的数据传输到I/O的另一端。

Channel是Java NIO提供的用来访问原生的I/O机制的一种途径,我们在编程时应该使用Buffer来和Channel交互,所以,Channel更像是I/O两端实体的桥梁。所谓的Buffer,是Channel用来发送和接收数据的端点。

20150930-java-channel-buffer.png

Channel的特点:

  • 与传统的流(stream)相比,Channel是双向的,既可以写,也可以读。
  • Channel可以把数据读进Buffer,也可以从Buffer里写数据。
  • Channel可以执行异步(asynchronous)的读写操作。
  • Channel可以支持阻塞(blocking)或者非阻塞(non-blocking)模式。
  • 非阻塞的Channel不会使调用的线程进入sleep模式。
  • 基于流的Channel(比如Socket)只能处于非阻塞模式。
  • 数据可以在Channel和Channel之间传输,前提是其中一个Channel是FileChannel。

Java NIO中的Channel类

以下是Java NIO包中提供的两种主要的Channel类实现:

  • FileChannel

    • 文件读写的Channel,不支持非阻塞模式。
  • SocketChannel

    • 有三种Socket Channel类,包括SocketChannel, ServerSocketChannel and DatagramChannel。
    • 可选择(selectable)的Channel,支持非阻塞模式。

一个Java NIO Channel的例子

下面这个例子从文本文件中读数据并且把内容打印到控制台中。我们使用RandomAccessFile和FileChannel把数据读取到ByteBuffer。我们读取512字节的数据到buffer,然后调用buffer的flip方法,使其准备好get操作。一旦我们把数据打印到控制台,我们调用buffer的clear方法,使其可以进行下一次读。如此,一直到文件的末尾。

package com.javapapers.java.nio;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelExample {
    public static void main(String args[]) throws IOException {
        RandomAccessFile file = new RandomAccessFile("temp.txt", "r");
        FileChannel fileChannel = file.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(512);
        while (fileChannel.read(byteBuffer) &gt; 0) {
            // flip the buffer to prepare for get operation
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()) {
                System.out.print((char) byteBuffer.get());
            }
            // clear the buffer ready for next sequence of read
            byteBuffer.clear();
        }
        file.close();
    }
}

下一篇,我们会详细看下Java NIO的Buffer和各种Channel类。

本文翻译自 javapapers文章 ,仅供参考和学习。