Java Channel

1、通道(Channel)的原理与获取

A.通道(Channel)

用于源节点与目标节点的连接。在Java NIO中负责缓冲区中的数据传输,
Channel本身不存储数据,因此需要配合缓冲区进行传输

B.通道的主要实现类

java.nio.channels.Channel接口:

实现类 IO
FileChannel 本地IO
SocketChannel TCP 网络IO
ServerSocketChannel
DatagramChannel UDP

C.获取通道的方式

①、Java针对支持通道的类提供了getChannel()方法

本地IO

FileInputStream/FileOutputStream
RandomAccessFile

网络IO:

Socket
ServerSocket
DatagramSocket

②、在jdk7中的NIO.2针对各个通道提供了静态方法open()

③、在jdk7中的NIO.2的File工具类的newByteChannel()

D.案例

①、利用通道完成文件的复制-非直接缓冲区方式

  1. // 利用通道完成文件的复制-非直接缓冲区
  2. public static void copyFileByChannel() {
  3. FileInputStream fileInputStream = null;
  4. FileOutputStream fileOutputStream = null;
  5. FileChannel fileInputStreamChannel = null;
  6. FileChannel fileOutputStreamChannel = null;
  7. try {
  8. fileInputStream = new FileInputStream("1.jpg");
  9. fileOutputStream = new FileOutputStream("2.jpg");
  10. // 1、获取通道
  11. fileInputStreamChannel = fileInputStream.getChannel();
  12. fileOutputStreamChannel = fileOutputStream.getChannel();
  13. // 2、分配指定大小的缓冲区
  14. ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  15. // 3、将通道中的数据存入缓冲区中
  16. while (fileInputStreamChannel.read(byteBuffer) != -1) {
  17. // 切换读数据模式
  18. byteBuffer.flip();
  19. // 4、将缓冲区中的数据写入通道中
  20. fileOutputStreamChannel.write(byteBuffer);
  21. // 清空缓冲区
  22. byteBuffer.clear();
  23. }
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. } finally {
  27. if (fileOutputStreamChannel != null) {
  28. try {
  29. fileOutputStreamChannel.close();
  30. } catch (IOException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. if (fileInputStreamChannel != null) {
  35. try {
  36. fileInputStreamChannel.close();
  37. } catch (IOException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. if (fileOutputStream != null) {
  42. try {
  43. fileOutputStream.close();
  44. } catch (IOException e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. if (fileInputStream != null) {
  49. try {
  50. fileInputStream.close();
  51. } catch (IOException e) {
  52. e.printStackTrace();
  53. }
  54. }
  55. }
  56. }

②、利用通道完成文件的复制-直接缓冲区的方式(内存映射文件)

  1. // 使用直接缓冲区完成文件的复制(内存映射文件)
  2. public static void copyFileByMappedByteBuffer() throws IOException {
  3. long start = System.currentTimeMillis();
  4. FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
  5. FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE_NEW);
  6. // 内存映射文件
  7. MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
  8. MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
  9. // 直接对缓冲区进行数据的读写操作
  10. byte[] bytes = new byte[inMappedBuf.limit()];
  11. inMappedBuf.get(bytes);
  12. outMappedBuf.put(bytes);
  13. inChannel.close();
  14. outChannel.close();
  15. long end = System.currentTimeMillis();
  16. System.out.println("直接缓冲区总耗费时间为:" + (end - start));
  17. }

2、通道的数据传输与内存映射

A.通道之间的数据传输

  • transferFrom()
  • transferTo()

    1. // 通道之间的数据传输(直接缓冲区)
    2. public static void channelDataTrans() throws IOException {
    3. long start = System.currentTimeMillis();
    4. FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    5. FileChannel outChannel = FileChannel.open(Paths.get("4.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE_NEW);
    6. // inChannel.transferTo(0, inChannel.size(), outChannel);
    7. outChannel.transferFrom(inChannel, 0, inChannel.size());
    8. inChannel.close();
    9. outChannel.close();
    10. long end = System.currentTimeMillis();
    11. System.out.println("直接缓冲区方式-通道数据传输数据复制文件-总耗费时间为:" + (end - start));
    12. }

    3、分散读取与聚集写入

    分散(Scatter)与聚集(Gather)

  • 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中

  • 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中

    A.分散读取(Scattering Reads)

    分散读取(Scattering Reads)是指从Channel中读取的数据“分散”到多个Buffer中。并且是按照缓冲区的顺序,从Channel中读取的数据依次将Buffer填满。
    image.png

    B.聚集写入(Gathering Writes)

    聚散写入(Gathering Writes)是指将多个Buffer中的数据“聚集”到Channel,按照缓冲区的顺序,写入position和limit之间的数据到Channel
    image.png

    C.案例

    1. /**
    2. * 分散读取和聚集写入
    3. *
    4. * @author Fcant 下午 21:31:30 2020/2/14/0014
    5. */
    6. public static void scatterAndGather() throws IOException {
    7. RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt", "rw");
    8. // 1.获取通道
    9. FileChannel fileChannel = randomAccessFile.getChannel();
    10. // 2.分配指定大小的缓冲区
    11. ByteBuffer byteBuffer = ByteBuffer.allocate(100);
    12. ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
    13. // 3.分散读取
    14. ByteBuffer[] buffers = {byteBuffer, byteBuffer1};
    15. fileChannel.read(buffers);
    16. for (ByteBuffer buffer : buffers) {
    17. buffer.flip();
    18. }
    19. System.out.println(new String(buffers[0].array(), 0, buffers[0].limit()));
    20. System.out.println("------------------");
    21. System.out.println(new String(buffers[1].array(), 0, buffers[1].limit()));
    22. // 4.聚集写入
    23. RandomAccessFile accessFile = new RandomAccessFile("2.txt", "rw");
    24. FileChannel accessFileChannel = accessFile.getChannel();
    25. accessFileChannel.write(buffers);
    26. }

    4、字符集Charset-编码与解码

  • 编码:字符串 -> 字节数组

  • 解码:字节数组 -> 字符串 ```java /**

    • 编码以及解码示例 *
    • @author Fcant 下午 21:03:45 2020/2/16/0016 */ public static void charSetEncodeDeCode() throws CharacterCodingException { Charset charset = Charset.forName(“GBK”); // 获取编码器 CharsetEncoder charsetEncoder = charset.newEncoder(); // 获取解码器 CharsetDecoder charsetDecoder = charset.newDecoder(); CharBuffer charBuffer = CharBuffer.allocate(1024); charBuffer.put(“樊乘乘”); charBuffer.flip(); // 编码 ByteBuffer byteBuffer = charsetEncoder.encode(charBuffer); for (int i = 1; i < 7; i++) {

      1. System.out.println(byteBuffer.get());

      } // 解码 byteBuffer.flip(); CharBuffer decode = charsetDecoder.decode(byteBuffer); System.out.println(decode.toString());

      System.out.println(“————————-以UTF-8编码格式进行解码————————“); Charset charsetUTF8 = Charset.forName(“UTF-8”); byteBuffer.flip(); CharBuffer charBufferUTF8 = charsetUTF8.decode(byteBuffer); System.out.println(charBufferUTF8.toString()); }

/**

  • 字符集 *
  • @author Fcant 下午 20:32:16 2020/2/15/0015 */ public static void aboutCharSet() { Map charsetMap = Charset.availableCharsets(); Set> entrySet = charsetMap.entrySet(); for (Map.Entry stringCharsetEntry : entrySet) {
    1. System.out.println(stringCharsetEntry.getKey() + "=" + stringCharsetEntry.getValue());
    } } ```