欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java学习笔记:NIO(NEW I/O)

程序员文章站 2024-02-16 10:33:46
...

java学习笔记:NIO(NEW I/O)

(一)为了实现更高效的I/O

(二)是对块进行处理,而不是对一个一个字节处理,这样会更高效。

(三)这里的块就是各种缓冲区,先把数据写到缓冲区中,然后将缓冲区的数据一并写到文件中。

(四)缓冲区类

  • ByteBuffer
  • ShortBuffer
  • CharBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer

(五)以ByteBuffer为例介绍其中的一些方法和属性

  1. 首先ByteBuffer类提供了一个静态方法来分配缓存的大小,
  2. ByteBuffer b = ByteBuffer.allocate(8);
  3. ByteBuffer对象中有三个重要的属性,position,limit,capacity,position表示将要把数据插入到哪个位置,随着插入完一个数据后自动加一,limit表示访问缓存中的数据的最大小标,比如limit=8,那么就只能访问到这里,capacity表示缓存大小,limit的初始值和capacity相等。
  4. put方法将数据放到缓存中,有多种写法。
  5. get从缓存中得到数据,在使用get的时候,如果传入的下标超过了limit则会报错java.lang.IndexOutOfBoundsException
  6. flip方法会将limit=position,然后把position变成0。目的是将缓存中存有数据的部分标明出来,而访问没有数据的部分的时候就会报错java.lang.IndexOutOfBoundsException
  7. hasRemaining()方法会返回position和limit之间是否有数据
  8. remaining()会返回position和limit之间有多少个数据,内部实现是limit-position
  9. 对属性和方法进行检验
 //创建一个大小为8的缓存
  ByteBuffer b = ByteBuffer.allocate(8);
  //输出一下position,limit,capacity属性
  System.out.println("position="+b.position());
  System.out.println("limit="+b.limit());
  System.out.println("capacity="+b.capacity());
  //添加数据10,20,30
  b.put((byte)10);
  b.put((byte)20);
  b.put((byte)30);
  
  System.out.println("-----------------");
  //再输出一下position,limit,capacity。
  //发现position已经变成3了说明,下一个插入的数据要放在3这个位置上
  System.out.println("position="+b.position());
  System.out.println("limit="+b.limit());
  System.out.println("capacity="+b.capacity());
  
  //flip一下
  b.flip();
  //发现limit变成了3,position变成了0 这个时候说明0到2有数据
  System.out.println("-----------------");
  System.out.println("position="+b.position());
  System.out.println("limit="+b.limit());
  System.out.println("capacity="+b.capacity());
  //检测是否有数据
  if(b.hasRemaining()) {
   //得到数据数,然后用for循环遍历数据
   for(int i = 0 ;i<b.remaining() ; i++) {
    System.out.println(b.get(i));
    
   }
  }


(六)通道类Channel,在通道里传输的是块(也就是缓存),用户把数据存到缓存中,然后缓存经过管道存到文件中,或者管道将文件读取到缓存中,用户从缓存中得到字节。
(七)可以通过FileInputStream的getChannel方法返回一个FileChannel对象,从管道读取的时候需要一个缓存,然后再把东西写道管道中。类死于流,但是管道的write方法只会把缓存的positon到limit之间的数据写到管道里,所以在写入管道前调用一下flip方法(如果没有读取满就用flip来调整缓存中的limit),读取完写入到管道中,然后清空一下缓存以便下一次读取。

//如果直接用new FileInputStreamy("D:\\test\\test1.txt").getChannel这种写法
  //虽然返回了一个管道但会打开一个流,而这个流有没有名字,也就无法关闭。
  //所以分开写
  InputStream is = new  FileInputStream("D:\\test\\test1.txt");
  FileChannel fcIn = ((FileInputStream) is).getChannel();
  OutputStream os = new FileOutputStream("D:\\test\\test3.txt");
  FileChannel fcOut = ((FileOutputStream) os).getChannel();
  ByteBuffer buf = ByteBuffer.allocate(1024);
  while(fcIn.read(buf)!=-1) {
   buf.flip();
   //这里write方法只会读取ByteBuffer对象中position到limit之间的数据
    fcOut.write(buf);
   //清空一下缓存
   buf.clear();
  }
  is.close();
  os.close();
  fcIn.close();
  fcOut.close();

(八)RandomAccessFile中的内存映射,以输入管道创建一个映射缓存,这个映射缓存
java学习笔记:NIO(NEW I/O)

RandomAccessFile read = new RandomAccessFile("D:\\test\\test1", "r");
  RandomAccessFile write = new RandomAccessFile("D:\\test\\test3", "rw");
  //获得输入输出管道
  FileChannel fcIn = read.getChannel();
  FileChannel fcOut = write.getChannel();
  //得到输入管道的长度
  long size = fcIn.size(); 
  //创建输入映射缓存,从0到size即把整个输入管道都映射到缓存中。
  //文件中所有的东西都会映射到缓存中。
  MappedByteBuffer inBuf = fcIn.map(MapMode.READ_ONLY, 0, size);
  //创建输出映射缓存,从0到size
  //所有映射缓存中的东西都会映射到文件中
  MappedByteBuffer outBuf = fcOut.map(MapMode.READ_ONLY, 0, size);
  //然后把输入映射缓存的东西全部写道输出映射缓存中,
  for(int i=0;i<size;i++) {
   outBuf.put(inBuf.get());
  }
  read.close();
  write.close();
  fcIn.close();
  fcOut.close();

(九)效率

  1. 映射
  2. 管道
  3. 带缓存的I/O
  4. 普通I/O