java NIO的基本用法

NIO的基本用法

1、什么是NIO

一种新IO流,可以实现对文件的读写操作,效率比IO流高

2、NIO和IO的区别

  • IO是面向流(Stream)的;NIO是面向通道(Channel)和缓冲区(Buffer)的,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中

  • IO流是阻塞的,这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。NIO是非阻塞的,NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变得可以读取之前,该线程可以继续做其他的事情。

3、NIO中的Channel的主要实现

  • FileChannel:文件通道

  • DatagramChannel:通过 UDP 读写网络中的数据通道。

  • SocketChannel:通过 TCP 读写网络中的数据

  • ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel

我们这里主要讲解FileChannel

4、NIO中的关键Buffer实现

NIO中的关键Buffer实现有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分别对应基本数据类型: byte, char, double, float, int, long, short。当然NIO中还有MappedByteBuffer, HeapByteBuffer, DirectByteBuffer等这里先不进行陈述。

5、缓冲区Buffer的基本属性

  • 容量 (capacity) :表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创建后不能更改。

  • 限制 (limit) :第一个不应该读取或写入的数据的索引,即位于 limit 后的数据不可读写。缓冲区的限制不能为负,并且不能大于其容量。

  • 位置 (position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制

    image-20200804201959667

6、FileChannel用法(实现文本复制)

a、方式一(读取文件到缓冲区)

public static void main(String[] args) throws IOException {
       //字节输入流
       FileInputStream fileInputStream=new FileInputStream(new File("object02/src/a.txt"));
       //字节输出流
       FileOutputStream fileOutputStream=new FileOutputStream(new File("object02/src/b.txt"));
       //获取通道,通过文件对应io流获取对应通道
       FileChannel fromFileChannel=fileInputStream.getChannel();
       FileChannel toFileChannel=fileOutputStream.getChannel();
       //创建缓冲区并分配空间
       ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
       //读取文件数据到缓冲区
       while (fromFileChannel.read(byteBuffer)!=-1){
           //设置缓冲区为读模式(看源码)
           byteBuffer.flip();
           //写数据
           toFileChannel.write(byteBuffer);
           //清空缓冲区(不清空缓冲区无法进行下一次读取,因为position=capacity,看源码)
           byteBuffer.clear();
      }
       //关闭资源
       fileInputStream.close();
       fileOutputStream.close();
       fromFileChannel.close();
       toFileChannel.close();
  }

b、方式二(通过channel的映射内存实现)

@Test
public void testCopyFile02() throws IOException
{
//建立1.mp4的通道(就是连接点), StandardOpenOption.READ打开读权限
FileChannel fileChannelA=FileChannel.open(Paths.get("d:/1.mp4"), StandardOpenOption.READ);
FileChannel fileChannelB=FileChannel.open(Paths.get("d:/2.mp4"),
StandardOpenOption.WRITE, //写权限
StandardOpenOption.READ, //读权限
StandardOpenOption.CREATE);//创建一个新的文件,如果该文件已经存在失败
//建立fileChannelA通道的映射内存,MapMode.READ_ONLY:只读,从0读到fileChannelA.size()
MappedByteBuffer inMappedBuf = fileChannelA.map(MapMode.READ_ONLY, 0, fileChannelA.size());
//建立fileChannelB通道的映射内存,MapMode.READ_WRITE:读写,从0读到fileChannelA.size()
MappedByteBuffer outMappedBuf = fileChannelB.map(MapMode.READ_WRITE, 0, fileChannelA.size());
//创建一个字节数组,存储读取的数据
byte[] dst = new byte[inMappedBuf.limit()];
  //从映射内存读取数据
inMappedBuf.get(dst);
  //将读取的数据写到d:/2.mp4
outMappedBuf.put(dst);
//关闭通道
fileChannelA.close();
fileChannelB.close();
}

c、方式三(方式二的简化)

    @Test
public void testCopyFile03() throws IOException
{
       //建立1.mp4的通道(就是连接点), StandardOpenOption.READ打开读权限
FileChannel fileChannelA=FileChannel.open(Paths.get("d:/1.mp4"), StandardOpenOption.READ);
FileChannel fileChannelB=FileChannel.open(Paths.get("d:/2.mp4"),
StandardOpenOption.WRITE, //写权限
StandardOpenOption.READ, //读权限
StandardOpenOption.CREATE);//创建一个新的文件,如果该文件已经存在失败
       //复制fileChannelA的内容到fileChannelB
fileChannelB.transferFrom(fileChannelA, 0, fileChannelA.size());
//关闭通道
fileChannelA.close();
fileChannelB.close();
}

 

 

 

 

记得快乐
原文地址:https://www.cnblogs.com/Y-wee/p/13435939.html