Java Nio

 1. 案例说明 NIO  的 Buffer

package com.example.netty.nio;

import java.nio.IntBuffer;

/**
 * java.nio.BufferOverflowException
 */
public class BasicBuffer {
    public static void main(String[] args) {
        //举例说明Buffer的使用
        //创建一个Buffer,大小为5,即可以存放5个int
        IntBuffer allocate = IntBuffer.allocate(5);
        //allocate.put(11);
        for (int i = 0; i < allocate.capacity(); i++) {
            allocate.put(i * 2);
        }
        //将buffer转换,读写切换
        allocate.flip();

        while (allocate.hasRemaining()) {
            System.out.println(allocate.get());
        }
    }
}

2. 应用实例 1-本地文件写数据(Channel:通道):

  1)   使用前面学习后的 ByteBuffer(缓冲)  和  FileChannel(通道),  将  "hello,尚硅谷"  写入到 file01.txt  中

  2)   文件不存在就创建

  3)   代码演示

package com.example.netty.nio;

import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NIOFileChannel01 {
    public static void main(String[] args) throws Exception {
        String str = "Hello Word";
        //创建一个输入流 -> channel
        FileOutputStream fileOutputStream = new FileOutputStream("d://file01.txt");

        //通过fileOutputStream 获取对应FileChannel
        //这个fileChannel真实类型是 FileChannelImpl
        FileChannel fileChannel = fileOutputStream.getChannel();

        //创建一个缓冲区 ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        //将str放入ByteBuffer
        byteBuffer.put(str.getBytes());

        //将ByteBuffer 进行 flip
        byteBuffer.flip();

        //将ByteBuffer 数据写入到FileChannel
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }
}

3. 本地文件读数据:

  1)   使用前面学习后的 ByteBuffer(缓冲)  和  FileChannel(通道), 将  file01.txt  中的数据读入到程序,并显示在控制台屏幕

  2)   假定文件已经存在

  3)   代码演示

package com.example.netty.nio;

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NIOFileChannel02 {
    public static void main(String[] args) throws Exception {
        File file = new File("d://file01.txt");
        //创建文件的输入流
        FileInputStream fileInputStream = new FileInputStream(file);

        //通过fileInputStream 获取对应的fileChannel -> 实际类型 FileChannelImpl
        FileChannel fileChannel = fileInputStream.getChannel();

        //创建缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length());

        //将通道的数据读入到 Buffer
        fileChannel.read(byteBuffer);

        //将byteBuffer的字节数据  转成String
        System.out.println(new String(byteBuffer.array()));
        fileInputStream.close();
    }
}

4:使用一个 Buffer 完成文件读取、写入

  实例要求:

  1)   使用  FileChannel(通道)  和  方法       read , write,完成文件的拷贝

  2)   拷贝一个文本文件  1.txt      ,  放在项目下即可

  3)   代码演示

package com.example.netty.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NIOFileChannel03 {
    public static void main(String[] args) throws Exception {

        FileInputStream fileInputStream = new FileInputStream(new File("d://file01.txt"));
        FileChannel fileInputStreamChannel = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream(new File("d://file02.txt"));
        FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(512);

        while (true) {  //循环读取
            int read = fileInputStreamChannel.read(byteBuffer);
            System.out.println("read:" + read);
            if (read == -1) {   //表示读完
                break;
            }
            //将buffer中的数据写入到    fileOutputStreamChannel -- 2.txt
            byteBuffer.flip();
            fileOutputStreamChannel.write(byteBuffer);
            byteBuffer.clear();
        }

        fileInputStream.close();
        fileOutputStream.close();
    }
}

5:拷贝文件 transferFrom  方法

  1)   实例要求:

  2)   使用  FileChannel(通道)  和  方法       transferFrom  ,完成文件的拷贝

  3)   拷贝一张图片

  4)   代码演示

package com.example.netty.nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class NIOFileChannel04 {
    public static void main(String[] args) throws IOException {
        //创建相关流
        FileInputStream fileInputStream = new FileInputStream("d://1.jpg");
        FileOutputStream fileOutputStream = new FileOutputStream("d://2.jpg");

        //获取各个流对应的fileChannel
        FileChannel fileInputStreamChannel = fileInputStream.getChannel();
        FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();

        //使用transferForm完成拷贝
        fileOutputStreamChannel.transferFrom(fileInputStreamChannel, 0 , fileInputStreamChannel.size());

        //关闭相关通道和流
        fileInputStream.close();
        fileOutputStream.close();
    }
}

 6. 关于 Buffer  和  Channel 的注意事项和细节:

  1)   ByteBuffer  支持类型化的 put  和  get, put  放入的是什么数据类型,get 就应该使用相应的数据类型来取出,否

则可能有  BufferUnderflowException  异常。[举例说明]

package com.example.netty.nio;

import java.nio.ByteBuffer;
//java.nio.BufferUnderflowException:Buffer内存溢出异常
public class NIOByteBufferPutGet {
    public static void main(String[] args) {
        //创建一个Buffer
        ByteBuffer buffer = ByteBuffer.allocate(64);

        //类型化方式放入数据
        buffer.putInt(100);
        buffer.putLong(1L);
        buffer.putShort((short) 4);
        buffer.putChar('上');

        //取出
        buffer.flip();

        System.out.println(buffer.getInt());
        System.out.println(buffer.getLong());
        System.out.println(buffer.getShort());
        System.out.println(buffer.getChar());
        System.out.println(buffer.getChar());
    }
}

  2)   可以将一个普通 Buffer  转成只读 Buffer [举例说明]

package com.example.netty.nio;

import java.nio.ByteBuffer;
//java.nio.ReadOnlyBufferException:Buffer只读异常
public class ReadOnlyBuffer {
    public static void main(String[] args) {
        //创建Buffer
        ByteBuffer buffer = ByteBuffer.allocate(64);

        for (int i = 0; i < 64; i++) {
            buffer.put((byte) i);
        }

        //读取
        buffer.flip();

        //得到一个只读Buffer
        ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
        System.out.println(readOnlyBuffer.getClass());

        //读取
        while (readOnlyBuffer.hasRemaining()) {
            System.out.println(readOnlyBuffer.get());
        }

        readOnlyBuffer.put((byte) 1);   //java.nio.ReadOnlyBufferException
    }
}

  3)   NIO  还提供了  MappedByteBuffer,  可以让文件直接在内存(堆外的内存)中进行修改,  而如何同步到文件,由 NIO  来完成. [举例说明]

package com.example.netty.nio;

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/*
说明:
1. MappedByteBuffer  可让文件直接在内存(堆外内存)修改,  操作系统不需要拷贝一次
*/
public class MappedByteBufferTest {
    public static void main(String[] args) throws Exception {
        RandomAccessFile randomAccessFile = new RandomAccessFile("d://1.txt", "rw");

        //获取相应的通道
        FileChannel channel = randomAccessFile.getChannel();

        /**
         *  参数 1: FileChannel.MapMode.READ_WRITE  使用的读写模式
         *  参数 2:  0  :  可以直接修改的起始位置
         *  参数 3:    5:  是映射到内存的大小(不是索引位置) ,即将  1.txt  的多少个字节映射到内存
         *  可以直接修改的范围就是  0-5
         *  实际类型  DirectByteBuffer
         */
        MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);

        mappedByteBuffer.put(0, (byte) 'H');
        mappedByteBuffer.put(2, (byte) '9');
        mappedByteBuffer.put(5, (byte) '9');//java.lang.IndexOutOfBoundsException:索引越界异常

        randomAccessFile.close();
        System.out.println("文件修改完成!");
    }
}

  4)   前面我们讲的读写操作,都是通过一个 Buffer  完成的,NIO  还支持  通过多个 Buffer (即  Buffer  数组)  完成读写操作,即  Scattering  和  Gathering  【举例说明】

原文地址:https://www.cnblogs.com/luliang888/p/12410664.html