piumnl
1/2/2017 - 11:08 AM

for ByteBuffer and FileChannel.

for ByteBuffer and FileChannel.

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * @author piumnl
 * @version 1.0.0
 * @since on 2017-01-02.
 */
public class ChannelDemo {

  @Test
  public void test_ChannelWriteFile() throws IOException {
    // 通过 FileChannel 实例将数据写入文件
    Path imlPath = Paths.get(System.getProperty("user.dir"), "io.iml");
    Path copyPath = imlPath.resolveSibling("copy.iml");
    Files.copy(imlPath, copyPath, StandardCopyOption.REPLACE_EXISTING);
    FileOutputStream out = new FileOutputStream(copyPath.toFile(), true);

    FileChannel channel = out.getChannel();

    ByteBuffer buffer = ByteBuffer.allocate(1024);

    buffer.put("xixi".getBytes());

    buffer.flip();        // limit = position; position = 0; mark = -1;
    channel.write(buffer);
    // 清空整个缓冲区,将所有标志位重置为初始化状态
    // buffer.clear();    // limit = capacity; position = 0; mark = -1;
    // buffer.compact();  // 只清除已读的缓冲,将未读数据放置在缓冲区的起始位置。
    // buffer.rewind();   // position = 0; mark = -1;
    // buffer.remaining();// limit - position,剩余多少可读
    // channel.force(true);// 强制立即写入到文件中

    out.close();
  }

  /**
   * 通过 FileChannel 实例读取文件
   */
  @Test
  public void test_ChannelReadFile() throws IOException {
    Path imlPath = Paths.get(System.getProperty("user.dir"), "io.iml");
    FileInputStream in = new FileInputStream(imlPath.toFile());
    FileChannel fileChannel = in.getChannel();
    ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());

    int result = fileChannel.read(byteBuffer);

    if (result != -1) {
      byteBuffer.flip();    // 将 position 重置为 0,将 limits 置为 原position
      String content = new String(byteBuffer.array(), StandardCharsets.UTF_8);
      System.out.println(content);
    }
    in.close();
  }

  /**
   * scatter:分散,将 Channel 实例中的数据拆分写入到多个 Buffer 中。
   */
  @Test
  public void test_ChannelScatter() throws IOException {
    ByteBuffer head = ByteBuffer.allocate(48);
    ByteBuffer body = ByteBuffer.allocate(512);
    ByteBuffer[] bufferArray = {head, body};

    Path imlPath = Paths.get(System.getProperty("user.dir"), "copy.iml");
    FileInputStream in = new FileInputStream(imlPath.toFile());
    FileChannel channel = in.getChannel();

    channel.read(bufferArray);
    in.close();

    body.flip();
    System.out.println(new String(head.array()));
    System.out.println(new String(body.array(), 0, body.remaining()));
  }

  /**
   * gather:聚合,按照数组的顺序将数据写入到 channel 中。
   */
  @Test
  public void test_ChannelGather() throws IOException {
    ByteBuffer head = ByteBuffer.allocate(48);
    ByteBuffer body = ByteBuffer.allocate(512);
    ByteBuffer[] bufferArray = {head, body};
    head.put("---------This is the head info.---------".getBytes());
    body.put("---------This is the body info.---------".getBytes());

    Path imlPath = Paths.get(System.getProperty("user.dir"), "copy.iml");
    FileOutputStream out = new FileOutputStream(imlPath.toFile(), true);
    FileChannel channel = out.getChannel();

    head.flip();
    body.flip();
    channel.write(bufferArray);
    out.close();

  }

  /**
   * Channel 实例的 transformTo() 方法
   * 此处还有一个 transformFrom() 方法,与 transformTo() 方法类似。
   */
  @Test
  public void test_transformTo() throws IOException {
    Path imlPath = Paths.get(System.getProperty("user.dir"), "copy.iml");
    RandomAccessFile randomAccess = new RandomAccessFile(imlPath.toFile(), "rw");
    FileChannel randomAccessChannel = randomAccess.getChannel();

    Path second = Paths.get(System.getProperty("user.dir"), "second.iml");
    if (Files.notExists(second)) {
      Files.createFile(second);
    }
    FileOutputStream out = new FileOutputStream(second.toFile());
    FileChannel outChannel = out.getChannel();

    // 在 SoketChannel 的实现中,SocketChannel 只会传输此刻准备好的数据 (可能不足 count 字节) 。
    // 因此,SocketChannel 可能不会将请求的所有数据 (count 个字节) 全部传输到 FileChannel 中。
    randomAccessChannel.transferTo(0, randomAccess.length(), outChannel);

    randomAccess.close();
    out.close();
  }
}