Java NIO - Scatter / Gather

897 阅读2分钟

Java NIO中内置了对散播器(scatter)和收集器(gather)的支持。我们知道一个channel可以把数据写到一个buffer中,也可以从一个buffer中把数据写到channel。事实上,一个channel可以同时和多个buffer协作。换句话说,可以把一个channel数据写到多个buffer,也可以读取多个buffer内容到一个channel

Scatter

我们可以把一个channel中的数据散播到多个buffer,这个过程就是把数据从一个channel写到多个buffer的过程,如下图:

scatter
下面代码展示了将Hello world读入到两个buffer中:

  private static void scattering(){
    ByteBuffer buffer1 = ByteBuffer.allocate(5);
    ByteBuffer buffer2 = ByteBuffer.allocate(5);
    ByteBuffer[] buffers = {buffer1,buffer2};
    try{
      FileChannel channel = new RandomAccessFile("d:\\temp1.txt","rw").getChannel();
      while (channel.read(buffers) != -1){
        display(buffers);
      }
      channel.close();
    }
    catch (IOException e){
      e.printStackTrace();
    }
  }

  private static void display(ByteBuffer[] buffers){
    for(ByteBuffer buffer: buffers){
      buffer.flip();
      while (buffer.hasRemaining()){
        System.out.print((char) buffer.get());
      }
      System.out.println();
      buffer.clear();
    }
  }

上面声明了两个ByteBuffer,每个长度都是5,temp.txt内容是:Hello world\r\n在执行channel.read(buffers)时,channel顺序地填充两个buffer,第一个buffer填满后填充第二个。如果两个都填满后,并且没有读取到文件尾,那么会继续循环填充:

  while (channel.read(buffers) != -1){
    display(buffers);
  }

Gather

对应Scatter,我们也可以把多个buffer中的内容写到同一个channel中,同样也是顺序填充

gather
下面代码展示了将两个buffer内容读入到channel

  private static void gathering(){
    ByteBuffer buffer1 = ByteBuffer.allocate(6);
    buffer1.put("hello ".getBytes());
    ByteBuffer buffer2 = ByteBuffer.allocate(6);
    ByteBuffer[] buffers = {buffer1,buffer2};
    buffer2.put("world!".getBytes());
    try{
      buffer1.flip();
      buffer2.flip();
      FileChannel channel = new RandomAccessFile("d:\\temp1.txt","rw").getChannel();
      channel.write(buffers);
      channel.close();
    }
    catch (IOException e){
      e.printStackTrace();
    }
    //validation
    scattering();
  }

上面代码展示了如何把多个buffer内容写道channel中,注意其中要的两行:

  buffer1.flip();
  buffer2.flip();

因为们先向他们写(put)了数据,此时需要把数据读到channel中,即需要从写模式切换到读模式,所以需要flip

注意:Scater一节中的display方法里也有flip(),因为我们向控制台输出的时候其实是先读取buffer内容,所以也要flip

参考

tutorials.jenkov.com/java-nio/sc…

blog.csdn.net/yhl_jxy/art…

练习

读取本地文件内容,然后实现scatter和gather过程