【Java基础】IO、NIO

本文深入解析Java NIO(New IO)的核心概念与操作,包括Channel、Buffer与Selector的使用,对比传统IO,介绍非阻塞I/O机制及内存映射文件的高效数据处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

IO

File类

IO原理

流的分类:

NIO(New IO)

NIO与IO区别

阻塞与非阻塞:

NIO核心:

1、Channel(通道)

利用通道完成文件的复制(非直接缓冲区)

利用直接缓冲区完成文件的赋值(内存映射文件)

通道之间的数据传输(直接缓冲区)

分散(Scatter)和聚集(Gather)

2、Buffer(缓冲)

类型、方法、属性

示例:

3、Selector(选择器)


IO

IO:Blocking IO 同步阻塞

使用输入机制,允许程序读取外部数据(包括俩字磁盘、光盘等存储设备的数据)、用户输入数据

使用输出机制,允许程序记录运行状态,将程序数据输出到磁盘、光盘等存储设备中。

File类

IO原理

IO流用来处理设备之间的数据传输。

Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。

 

流的分类:

 

Java使用处理流来包装节点流是一种典型的装饰器设计模式。

NIO(New IO)

 

NIO与IO区别

阻塞与非阻塞:

 

 

NIO核心:

若使用NIO系统,需要获取用于连接IO设备的通道一级用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。

采用内存映射文件的方式来处理输入/输出。将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了,这种方式比传统的要快。

Channel负责传输,Buffer负责存储。Channel类似于铁路,Buffer类似于火车。

1、Channel(通道)

类似于:铁路

通道表示打开IO设备(例如:文件、套接字)的连接。Channel本身不存储数据,只能与Buffer进行交互。

所有数据都需要通过通道传输;Channel与传统的InputStream、OutputStream的最大区别在于:它提供了一个map()方法,通过该map()方法可以直接将“一块数据”映射到内存中。如果传统的面向流,则NIO面向块的处理。

 

利用通道完成文件的复制(非直接缓冲区)

// 利用通道完成文件的复制(非直接缓冲区)
    @Test
    public void test2() throws IOException {

        
        FileInputStream fis = null;
        FileOutputStream fos = null;

        // 获取通道
        FileChannel inChannel = null;
        FileChannel outChannel = null;

        try {
            fis = new FileInputStream("G:\\学习资料2019\\nio\\1.jpg");
            fos = new FileOutputStream("2.jpg");

            // 获取通道
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();

            // 分配指定大小的缓冲区
            ByteBuffer buf = ByteBuffer.allocate(1024);

            // 将通道中的数据存入缓冲区
            while (inChannel.read(buf) != -1) {
                buf.flip(); // 切换读取数据的模式
                // 将缓冲区中的数据写入通道中
                outChannel.write(buf);
                buf.clear();// 清空缓存区
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

利用直接缓冲区完成文件的赋值(内存映射文件)

// 使用直接缓冲区完成文件的复制(内存映射文件)
    @Test
    public void test3() throws IOException{
        long start = System.currentTimeMillis();
        FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ, StandardOpenOption.CREATE);
        // 内存映射文件
        MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
        MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());

        // 直接对缓冲区进行数据的读写操作
        byte[] dst = new byte[inMappedBuf.limit()];
        inMappedBuf.get(dst);
        outMappedBuf.put(dst);

        inChannel.close();
        outChannel.close();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

通道之间的数据传输(直接缓冲区)

   // 通道之间的数据传输
    @Test
    public void test4() throws IOException {
        FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("5.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ, StandardOpenOption.CREATE);

        //        inChannel.transferTo(0,inChannel.size(),outChannel);
        outChannel.transferFrom(inChannel,0,inChannel.size());
        inChannel.close();
        outChannel.close();
    }

分散(Scatter)和聚集(Gather)

 

 

分散读取:

 @Test
    public void test5() throws IOException{
        RandomAccessFile raf1 = new RandomAccessFile("1.txt","rw");

        // 获取通道
        FileChannel channel =  raf1.getChannel();

        // 分配指定大小的缓冲区
        ByteBuffer buf1 = ByteBuffer.allocate(1);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        // 分散读取
        ByteBuffer[] bufs = {buf1,buf2};
        channel.read(bufs);

        for (ByteBuffer byteBuffer:bufs
             ) {
            byteBuffer.flip();
        }
        System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));;
        System.out.println("-------------------------------");
        System.out.println(new String (bufs[1].array(),0,bufs[1].limit()));
    }

聚集写入:

 @Test
    public void test5() throws IOException{
        RandomAccessFile raf1 = new RandomAccessFile("1.txt","rw");

        // 获取通道
        FileChannel channel =  raf1.getChannel();

        // 分配指定大小的缓冲区
        ByteBuffer buf1 = ByteBuffer.allocate(1);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        // 分散读取
        ByteBuffer[] bufs = {buf1,buf2};
        channel.read(bufs);

        for (ByteBuffer byteBuffer:bufs
             ) {
            byteBuffer.flip();
        }
        System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));;
        System.out.println("-------------------------------");
        System.out.println(new String (bufs[1].array(),0,bufs[1].limit()));

        // 聚集写入
        RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
        FileChannel channel2 = raf2.getChannel();

        channel2.write(bufs);
    }

 

2、Buffer(缓冲)

类似于:火车

负责数据的存取。

可以理解成一个容器,本质是一个数组,发送到Channel中的所有对象都必须首先放到Buffer中,从而Channel中读取的数据也必须先放到Buffer中。

Buffer可以一次次去Channel中共取数据,也允许Channel直接将文件的某块数据映射成Buffer。

类型、方法、属性

 

示例:

  @Test
    public void test1() {
        System.out.println("--------------allocate-------------------");
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());
        System.out.println("-----------------put----------------");
        // 利用put存入数据到缓冲区
        String str = "abcde";
        byteBuffer.put(str.getBytes());
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());
        System.out.println("-----------------flip()----------------");
        // 切换到读取数据的模式
        byteBuffer.flip();
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());
        System.out.println("-----------------get()----------------");
        // 利用get()读取缓冲区中的数据
        byte[] bytes = new byte[byteBuffer.limit()];
        byteBuffer.get(bytes);
        System.out.println(new String(bytes, 0, bytes.length));
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());
        System.out.println("-----------------rewind()----------------");
        // 可重复读数据
        byteBuffer.rewind();
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());
        System.out.println("-----------------clear()----------------");
        // clear()清空缓冲区,但是缓冲区中的数据依然存在,但是处于“被遗忘状态”,不能正确的读取数据
        byteBuffer.clear();
        System.out.println(byteBuffer.capacity());
        System.out.println(byteBuffer.limit());
        System.out.println(byteBuffer.position());


    }

3、Selector(选择器)

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值