• java基础---NIO


    NIO

    从 JDK1.4 开始 Java 引入了一系列改进的输入 / 输出处理的新功能,统称为 NIO ,即新 IO ,新增了许多用于处理输入输出的类,新IO 采用内存映射文件的方式处理输入输出,新 IO 将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件,这种方式进行输入输出比传统的输入输出快的多

    NIO基础

    Channel 通道和 Buffer 缓冲是 NIO 中的两个核心对象
    • Chanel是对传统输入输出系统的模拟,通过map方法可以将一块数据映射到内存中
    • Buffer本质是一个数组,发送到Channel中的所有对象都必须先放到Buffer中,而从Channel中读取的数据必须先放到Buffer中

    NIO和多路复用的区别

    IO 模型
    • 同步阻塞IO(Blocking IO):即传统的IO模型
    • 同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库
    • 多路复用IO(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型
    • 异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO。
    java NIO 就是采用多路复用 IO 模式
    在多路复用 IO 模型中,会有一个线程( Java 中的 Selector )不断去轮询多个 socket 的状态,只有当socket真正有读写事件时,才真正调用实际的 IO 读写操作。因为在多路复用 IO 模型中,只需要使用一个线程就可以管理多个socket ,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket 读写事件进行时,才会使用 IO 资源,所以它大大减少了资源占用。

    Buffer的使用

    Buffer 是一个抽象类,主要作用是用于装入数据,然后输出数据
    • 最常见的子类ByteBuffer可以在底层字节数组上进行get/set操作
    • 其它基本数据类型都有对应的Buffer类:CharBuffer、 ShortBuffer、 IntBuffer、 LongBuffer、FloatBuffer、 DoubleBuffer
    静态方法 static XxxBuffer allocate(int capacity) 创建一个容量为 capacity 的 XxxBuffer 对象
    Buffer 中有 3 个重要概念:容量 capacity 、界限 limit 和位置 position
    • 容量capacity表示该Buffer的最大数据容量,创建后则不能改变
    • 界限limit,位于limit后的数据既不可被读,也不可被写
    • 位置position用于指明下一个可以被读出的或者写入缓冲区的位置索引
    • 标记mark位置
    Buffer 的 position 为 0 , limit 为 capacity ,程序可以通过 put 方法向 Buffer 写入一些数据,每放入一些数据,Buffer 的 position 响应的向后移动。

    读文件、写文件操作

    1. package com.yan3;
    2. import java.io.File;
    3. import java.io.FileInputStream;
    4. import java.nio.ByteBuffer;
    5. import java.nio.channels.FileChannel;
    6. public class Test2 {
    7. public static void main(String[] args) throws Exception {
    8. File file = new File("data/nio.data");
    9. FileInputStream fis = new FileInputStream(file);
    10. FileChannel channel = fis.getChannel();// channel管道
    11. ByteBuffer buffer = ByteBuffer.allocate((int) file.length());//
    12. int len = 0;
    13. while ((len = channel.read(buffer)) > 0) {
    14. buffer.clear();
    15. byte[] arr = buffer.array();
    16. String ss = new String(arr, 0, len);
    17. System.out.println(ss);
    18. }
    19. }
    20. }
    21. /*
    22. * Buffer是一个抽象类,主要作用是用于装入数据,然后输出数据
    23. *
    24. * - 最常见的子类ByteBuffer可以在底层字节数组上进行get/set操作 - 其它基本数据类型都有对应的Buffer类:CharBuffer、
    25. * ShortBuffer、 IntBuffer、 LongBuffer、 FloatBuffer、 DoubleBuffer
    26. *
    27. * 静态方法static XxxBuffer allocate(int capacity)创建一个容量为capacity的XxxBuffer对象
    28. *
    29. * Buffer中有3个重要概念:容量capacity、界限limit和位置position -
    30. * 容量capacity表示该Buffer的最大数据容量,创建后则不能改变 - 界限limit,位于limit后的数据既不可被读,也不可被写 -
    31. * 位置position用于指明下一个可以被读出的或者写入缓冲区的位置索引 - 标记mark位置
    32. *
    33. * Buffer的position为0,limit为capacity,程序可以通过put方法向Buffer写入一些数据,
    34. * 每放入一些数据,Buffer的position响应的向后移动。
    35. */
    1. package com.yan3;
    2. import java.io.FileOutputStream;
    3. import java.nio.ByteBuffer;
    4. import java.nio.channels.FileChannel;
    5. import java.nio.charset.StandardCharsets;
    6. public class Test1 {
    7. public static void main(String[] args) throws Exception {
    8. FileOutputStream fos = new FileOutputStream("data/nio.data");
    9. FileChannel channel = fos.getChannel();
    10. ByteBuffer buffer = StandardCharsets.UTF_8.encode("内蒙人喜欢骑马射箭1");
    11. int len = 0;
    12. while ((len = channel.write(buffer)) != 0) {
    13. System.out.println(len);
    14. }
    15. fos.close();
    16. }
    17. }

    Buffer类的常用方法

    • capacity():int返回Buffer的容量大小
    • hasRemaining():boolean判断是否还有元素可以进行处理
    • remaining():int返回当前位置和界限之间的元素个数
    • position():int返回当前操作的位置
    • mark():Buffer设置Buffer的标记位置,只能在0和position之间做标记
    • reset():Buffer将位置position转到mark所在的位置
    • rewind():Buffer将位置position设置到0,取消设置的mark
    • put(obj)用于向Buffer中放入数据
    • get()用于从Buffer中取出数据
    1. package com.yan3;
    2. import java.nio.CharBuffer;
    3. /*
    4. * #### Buffer类的常用方法
    5. - capacity():int返回Buffer的容量大小
    6. - hasRemaining():boolean判断是否还有元素可以进行处理
    7. - remaining():int返回当前位置和界限之间的元素个数
    8. - position():int返回当前操作的位置
    9. - mark():Buffer设置Buffer的标记位置,只能在0和position之间做标记
    10. - reset():Buffer将位置position转到mark所在的位置
    11. - rewind():Buffer将位置position设置到0,取消设置的mark
    12. - put(obj)用于向Buffer中放入数据
    13. - get()用于从Buffer中取出数据
    14. */
    15. public class Test3 {
    16. public static void main(String[] args) {
    17. // 创建对应的buffer对象,其中最大容积值为10
    18. CharBuffer buffer = CharBuffer.allocate(10);
    19. System.out.println(buffer.capacity());// 10 获取buffer的容积值capacity=10,position=0,limit=10
    20. System.out.println(buffer.position());// 0
    21. System.out.println(buffer.limit());// 10
    22. buffer.put('中');
    23. System.out.println(buffer.capacity());// 10
    24. System.out.println(buffer.position());// 1 char
    25. System.out.println(buffer.limit());// 10
    26. String ss = "中国人民解放军";
    27. for (int i = 0; i < ss.length(); i++)
    28. buffer.put(ss.charAt(i));
    29. System.out.println(buffer.capacity());// 10
    30. System.out.println(buffer.position());// 8 char
    31. System.out.println(buffer.limit());// 10
    32. // 将limit设置到position,并且把position设置为0。
    33. // 相当于是将buffer中没有数据的存储位置封印起来,从而避免读取时读到不合法的数据
    34. buffer.flip();
    35. System.out.println(buffer.capacity());// 10
    36. System.out.println(buffer.position());// 0
    37. System.out.println(buffer.limit());// 8
    38. char cc = buffer.get();// 获取position对应的字符
    39. System.out.println(cc); // 中
    40. System.out.println(buffer.capacity());// 10
    41. System.out.println(buffer.position());// 1
    42. System.out.println(buffer.limit());// 8
    43. buffer.clear();// 重置position和limit,可以理解为清理limit限制,并不是清空内容
    44. System.out.println(buffer.capacity());// 10
    45. System.out.println(buffer.position());// 0
    46. System.out.println(buffer.limit());// 10
    47. // System.out.println(buffer.get()); // 中
    48. ss = "中国人民解放军";
    49. for (int i = 0; i < ss.length(); i++)
    50. buffer.put(ss.charAt(i));
    51. cc = buffer.get(2);// 按照下标位置获取对应的数据,并不会操作position
    52. System.out.println(cc);
    53. System.out.println(buffer.position());// 7
    54. System.out.println(buffer.get(7));// 军
    55. System.out.println((int) buffer.get(8));// 空
    56. }
    57. }

    Channel类的常用方法

    Channel 可以直接将文件的部分或者全部直接映射成 Buffer
    注意:不能直接访问 Channel 中的数据,包括读取、写入都不行。 Channel 只能与 Buffer 进行交互
    • 所有Channel不应该通过构造器来直接创建,而是通过传统的节点InputStream、OutputStream的getChannel方法来返回对应的Channel
    • 常用的是FileInputStream、FileOutputStream的getChannel()返回的FileChannel
    Channel 中最常用的三个方法是 map() 、 read() 和 write()
    1. package com.yan3;
    2. import java.io.FileInputStream;
    3. import java.io.FileOutputStream;
    4. import java.io.IOException;
    5. import java.io.InputStream;
    6. import java.io.OutputStream;
    7. public class Test41 {
    8. public static void main(String[] args) throws IOException {
    9. byte[] buffer = new byte[8192];
    10. InputStream is = new FileInputStream("data/Test1.java");
    11. OutputStream os = new FileOutputStream("data/Test1.bak");
    12. int len = 0;
    13. while ((len = is.read(buffer)) > 0) {
    14. os.write(buffer, 0, len);
    15. }
    16. os.close();
    17. is.close();
    18. }
    19. }
    异常: java.nio.charset.MalformedInputException 一般是编码转换时由于编码字符集错误导致的,可以修改Charset 中编码字符集名称解决。例如 GBK 、 UTF-8 等
    map() 方法将 Channel 对应的部分或全部数据映射成 ByteBuffer
    1. package com.yan3;
    2. import java.io.File;
    3. import java.io.FileInputStream;
    4. import java.io.FileOutputStream;
    5. import java.nio.CharBuffer;
    6. import java.nio.MappedByteBuffer;
    7. import java.nio.channels.FileChannel;
    8. import java.nio.charset.Charset;
    9. import java.nio.charset.CharsetDecoder;
    10. /*
    11. * map()方法将Channel对应的部分或全部数据映射成ByteBuffer
    12. */
    13. public class Test42 {
    14. public static void main(String[] args) throws Exception {
    15. File f = new File("data/Test1.java");
    16. FileChannel in = new FileInputStream(f).getChannel();
    17. FileChannel out = new FileOutputStream("data/a.txt").getChannel();
    18. MappedByteBuffer buffer = in.map(FileChannel.MapMode.READ_ONLY, 0, f.length());// 参数1为执行映射时的模式,有只读、读写模式;参数2和3用于设置哪些数据执行映射。可以将FileChannel中全部数据映射为ByteBuffer
    19. out.write(buffer);
    20. buffer.clear();
    21. Charset charset = Charset.forName("UTF-8");
    22. CharsetDecoder decoder = charset.newDecoder();
    23. CharBuffer cb = decoder.decode(buffer);
    24. System.out.println(cb);
    25. }
    26. }
    写入数据
    1. package com.yan3;
    2. import java.io.File;
    3. import java.io.IOException;
    4. import java.io.RandomAccessFile;
    5. import java.nio.ByteBuffer;
    6. import java.nio.channels.FileChannel;
    7. import java.nio.channels.FileChannel.MapMode;
    8. /*
    9. * 写入数据
    10. */
    11. public class Test43 {
    12. public static void main(String[] args) throws IOException {
    13. File file = new File("data/a.txt");
    14. int len = (int) file.length();
    15. RandomAccessFile raf = new RandomAccessFile(file, "rw");
    16. FileChannel channel = raf.getChannel();// 返回的channel是只读还是读写,取决于RandomAccessFile文件对象的打开模式
    17. ByteBuffer buffer = channel.map(MapMode.READ_ONLY, 0, len);// buffer支持可读,将文件中的所有内容映射到buffer中
    18. channel.position(len); // 移动指针到内容末尾
    19. channel.write(buffer); // 重新写出buffer中的内容,实际上就是将文件内容拷贝
    20. }
    21. }

  • 相关阅读:
    人工神经网络的基本属性,神经网络四个基本属性
    JavaSE - 运算符(操作符)
    学习自由模态试验的有限元仿真计算方法
    算法学习的积累
    向新而生保业务增长,亚信科技持续锻造“核心引擎”
    Linux之Nignx及负载均衡&动静分离
    持续集成部署 - Jenkins 配置使用远程服务器的 Docker 执行构建任务
    springboot云农门户产品中心子系统
    傅里叶变换
    农村科学实验杂志农村科学实验杂志社农村科学实验编辑部2022年第12期目录
  • 原文地址:https://blog.csdn.net/tiger_root/article/details/126310461