Java NIO(缓冲区Buffer、通道Channel)、Files类

一、小案例

  1. 需求:我有一个文本文件,我知道数据是键值对形式的,但是不知道内容是什么。请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为”100”
        public static void main(String[] args) throws IOException {
        //读取文件,把键值读取到集合里
        Properties properties = new Properties();
        properties.load(new FileReader("User.properties"));
        //判断是否这个键存在,有就改
        if(properties.containsKey("lisi")){
            properties.setProperty("lisi","100");//键相同,值覆盖
        }
        properties.store(new FileWriter("User.properties"),null);
    }
  1. 将一个music.mp3文件,拆分成多个小文件,再将多个小文件,合并成一个mp3文件
//将一个文件,拆分成多个小文件
FileInputStream in = new FileInputStream("歌曲串烧.mp3");
        //我们封装一个文件夹,放我们拆分的文件
        File file = new File("E:\\歌曲大合集");
        if(!file.exists()){
            file.mkdirs();
        }
        //拆分
        int len=0;
        byte[] bytes = new byte[1024 * 1024];
        int index=1;
        while((len=in.read(bytes))!=-1){
            FileOutputStream out = new FileOutputStream(new File(file, index + ".mp3"));
            out.write(bytes,0,len);
            out.close();
            index++;
        }
        in.close();
//将多个小文件,合并成一个大的文件
File file = new File("E:\\歌曲大合集");
        File[] files = file.listFiles();
        Vector<FileInputStream> vector = new Vector<>();
        for (File f : files) {
            FileInputStream in = new FileInputStream(f);
            vector.add(in);
        }
        Enumeration<FileInputStream> elements = vector.elements();
        SequenceInputStream sequenceInputStream = new SequenceInputStream(elements);
        FileOutputStream out = new FileOutputStream(new File(file,"合并.mp3"));
        int len=0;
        byte[] bytes = new byte[1024 * 1024];
        while((len=sequenceInputStream.read(bytes))!=-1){
            out.write(bytes,0,len);
            out.flush();
        }
        out.close();
        sequenceInputStream.close();
        
        //合并之后,把小文件删掉
        for (File ff : files) {
            if(ff.length()<=1024*1024){
                ff.delete();
            }

二、Java NIO

1.Java NIO的简介

Java NIO是从Java1.4版本开始引入的一个新的IO API。可以代替标准的Java IO API。NIO与原来的IO有相同的作用和目的,但是使用方式完全不同,NIO支持面向缓冲区、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

2.Java IO与NIO的区别
IONIO
面向流面向缓冲区
阻塞IO非阻塞IO
(无)选择器
3.通道Channel与缓冲区Buffer
  1. java NIO系统的核心在于:通道Channel与缓冲区Buffer
  2. 通道负责传输,缓冲区负责存储

三、缓冲区Buffer

缓冲区Buffer:一个用于基本数据类型的容器。由java.nio包定义的,所有缓冲区都是Buffer抽象类的子类
Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入缓冲区的,是从缓冲区写入通道的

Buffer缓冲区底层是数组,它的总用就是用来存储数据的
        针对基本数据类型(布尔类型除外),都提供有相应的缓冲区
        
        ByteBuffer 字节缓冲区,最常用
        ShortBuffer
        IntBuffer
        LongBuffer

        FloatBuffer
        DoubleBuffer
        CharBuffer
1.缓冲区的基本属性与方法

position位置:文件指针,从position开始可以读数据。缓冲区的位置不能大于其限制
limit界限:从limit往后的数据不可读写。缓冲区的限制不能大于容量
capacity缓冲区的容量,一旦指定容量后,就不能更改。缓冲区容量不能为负

        //分配一个缓冲区,指定容量为十个字节
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//10
        //往容器中放数据put()
        String str="abcde";
        byteBuffer.put(str.getBytes());
        System.out.println(byteBuffer.position());//5
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//10
        //读取缓冲区里的数据,切换为读取模式
        byteBuffer.flip();
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//5
        //读取数据
        byte[] bytes = new byte[byteBuffer.limit()];
        byteBuffer.get(bytes);
        System.out.println(new String(bytes, 0, byteBuffer.limit()));//abcde
        System.out.println(byteBuffer.position());//5
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//5
        //可重复读取
        byteBuffer.rewind();
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//5
        //清空缓冲区
        byteBuffer.clear();//clear()并不是把缓冲区里的字节数据清掉,而是把这些指针,设置到初始状态
        System.out.println(byteBuffer.position());//0
        System.out.println(byteBuffer.capacity());//10
        System.out.println(byteBuffer.limit());//10
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        String str="abcde";
        byteBuffer.put(str.getBytes());

        byteBuffer.flip();//切换读取模式
        byte[] bytes = new byte[byteBuffer.limit()];
        byteBuffer.get(bytes, 0, 2);//读取两个字节
        System.out.println(byteBuffer.position());

        byteBuffer.mark();//mark()标记,标记当前position的位置

        byteBuffer.get(bytes,0,2);//在读取两个字节
        System.out.println(byteBuffer.position());

        byteBuffer.reset();//使用reset()就可以回到上次标记的位置
        System.out.println(byteBuffer.position());

        if(byteBuffer.hasRemaining()){
            System.out.println(byteBuffer.remaining());//hasRemaining()看一下还有没有可读数据
        }//remaining()还有多少可读数据
2.直接缓冲区与非直接缓冲区

缓冲区分为:直接缓冲区与非直接缓冲区
直接缓冲区:将缓冲区建立在物理内存上
非直接缓冲区:将缓冲区建立在JVM的内存上

//非直接缓冲区allocate(1024)
        ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
//直接缓冲区allocateDirect(1024)
        ByteBuffer byteBuffer2= ByteBuffer.allocateDirect(1024);

四、通道Channel

Channel通道,连接源节点与目标节点,不能存储数据
java为Channel接口提供的最主要的实现类如下:

  1. 本地文件传输通道
    FileChannel:用于读取、写入、映射和操作文件的通道
  2. 网络数据传输通道
    DatagramChannel :通过 UDP 读写网络中的数据通道
    SocketChannel :通过 TCP 读写网络中的数据。
    ServerSocketChannel :可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel
1.获取通道
  1. 方式一:FileOutputStream、FileInputStream、RandomAccessFile
    通过getChannel();获取通道
//非直接缓冲区复制文件
    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("曾经的你.mp3");
        FileOutputStream out = new FileOutputStream("曾经的你2.mp3");

        FileChannel inChannel = in.getChannel();
        FileChannel outChannel = out.getChannel();//获取通道
        //面向通道与缓冲区来复制文件
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//分配一个非直接缓冲区
        //读写文件
        while(inChannel.read(byteBuffer)!=-1){
            byteBuffer.flip();//切换读写模式
            outChannel.write(byteBuffer);//写数据
            byteBuffer.clear();//清空缓冲区
        }
        //释放资源
        in.close();
        out.close();
        inChannel.close();
        outChannel.close();
    }
  1. 方式二:通过FileChannel的静态方法open()来打开一个通道
//非直接缓冲区复制文件
        FileChannel inChannel = FileChannel.open(Paths.get("曾经的你.mp3"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("曾经的你2.mp3"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //StandardOpenOption.CREATE_NEW 文件不存在就创建,存在就报错
        //StandardOpenOption.CREATE  文件不存在就创建,存在就覆盖
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//分配非直接缓冲区
        while(inChannel.read(byteBuffer)!=-1){
            byteBuffer.flip();//切换读取模式
            outChannel.write(byteBuffer);
            byteBuffer.clear();//清空
        }
        //释放资源
        inChannel.close();
        outChannel.close();
  1. 直接缓冲区复制文件
        FileChannel inChannel = FileChannel.open(Paths.get("曾经的你.mp3"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("曾经的你2.mp3"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //建立直接缓冲区
        MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
        //把数据读取到缓冲区中
        byte[] bytes = new byte[inMap.limit()];
        inMap.get(bytes);
        outMap.get(bytes);
        inChannel.close();
        outChannel.close();
  1. 通道中的数据传输
  //通道中的文件传输
        FileChannel inChannel = FileChannel.open(Paths.get("曾经的你.mp3"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("曾经的你2.mp3"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //1.站在输入通道的角度
        inChannel.transferTo(0,inChannel.size(),outChannel);
        //2.站在输出通道的角度
        outChannel.transferFrom(inChannel,0,inChannel.size());
  1. 分配多个缓冲区来进行文件的传输
        FileChannel inChannel = FileChannel.open(Paths.get("MyTest3.java"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("MyTest.java"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
        //分配多个缓冲区
        ByteBuffer byteBuffer1 = ByteBuffer.allocate(100);
        ByteBuffer byteBuffer2= ByteBuffer.allocate(1024 * 2);
        //定义一个数组
        ByteBuffer[] byteBuffers ={byteBuffer1,byteBuffer2};
        inChannel.read(byteBuffers);
        //聚集
        for (ByteBuffer byteBuffer : byteBuffers) {
            byteBuffer.flip();//转换成读取模式
        }

        outChannel.write(byteBuffers);//写出数据
        inChannel.close();
        outChannel.close();//释放资源
  1. 获取通道的第三种方式
    JDK1.7之后提供了一个工具类Files newByteChannel()
FileChannel in =(FileChannel) Files.newByteChannel(Paths.get("demo.txt"), StandardOpenOption.READ);
FileChannel out =(FileChannel)Files.newByteChannel(Paths.get("demo111.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

五、Files类

1.Files类中复制文件的方法
        Files.copy(Paths.get("a.txt"), Paths.get("b.txt"), StandardCopyOption.REPLACE_EXISTING);

        Files.copy(new FileInputStream("a.txt"), Paths.get("b.txt"), StandardCopyOption.REPLACE_EXISTING);

        Files.copy(Paths.get("a.txt"), new FileOutputStream("b.txt"));
         //复制文件,参1;源文件路径,参数2:目标文件路径
         //StandardCopyOption.REPLACE_EXISTING 可选参数,文件存在,就覆盖
         //不给第三个参数,文件存在就报错,也就是多次复制,就报错

Files.move(Paths.get("a.txt"), Paths.get("D:\\b.txt"));//移动剪切文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值