美文网首页
JavaNIO-通道02 FileChannel 文件操作

JavaNIO-通道02 FileChannel 文件操作

作者: 贪睡的企鹅 | 来源:发表于2019-07-17 19:00 被阅读0次

    1 FileChannel 概述

    • FileChannel 类的主要作用是读取、写入、映射和操作文件的通道。该通道永远是阻塞
      的操作。
    • FileChannel 类在内部维护当前文件的position ,可对其进行查询和修改。

    2 FileChannel 类结构

    image

    核心功能

    1 读取、写入和关闭通道文件。
    2 以不影响通道当前位置(position)的方式,对文件中绝对位置的字节进行读取或写人。
    3 MMAP,将文件中的某个区域直接映射到程序用户态内存中(用户态)。对于较大的文件,这通常比调用普通的 read ()或write ()方法更为高效。
    4 强制对底层存储设备进行文件的更新(内存刷入磁盘),确保在系统崩溃时不丢失数据。
    5 SendFile 零拷贝文件数据读写拷贝
    6 可以锁定某个文件区域,以阻止其他程序对其进行访问。
    7 多个并发线程可安全地使用文件通道。

    3 核心API 使用

    1 write(ByteBuffer buffer)

    从给定缓冲区读取能数据(limit-position),从通道设置position位置写入。

    • position > file.size 写入position之前位置补空位。
    • 通道中position伴随写入而移动。
    • 多线程同步

    写入案例

    @Test
        public void test_write() throws Exception {
    
    
            RandomAccessFile readFile = new RandomAccessFile("write1.txt", "rw");
            RandomAccessFile writeFile = new RandomAccessFile("write1.txt", "rw");
            FileChannel fileChannel = writeFile.getChannel();
            FileChannel fileChannel2 = readFile.getChannel();
    
    
            /** 设置文件写入位置 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer=ByteBuffer.wrap("abcd".getBytes());
    
                /** 写入文件字节缓冲区数据 **/
                buffer.position(1);
                buffer.limit(2);
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                /** 写入文件之后的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
                System.out.println();
    
                /** 重置缓冲区 **/
                buffer.position(1);
                buffer.limit(2);
                System.out.println ("A fileChannel.position ()= " + fileChannel.position()) ;
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                System.out.println ("A fileChannel.position ()= " + fileChannel.position()) ;
    
    
                ByteBuffer allocate = ByteBuffer.allocate(8);
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
        
    fileChannel.position= 0
    write() size= 1
    fileChannel.position= 1
    
    A fileChannel.position ()= 1
    write() size= 1
    A fileChannel.position ()= 2
    bb   
    

    多线程同步案例

    public void test_write2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write2.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                IntStream.range(0,10).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer=ByteBuffer.wrap("abcd\r\n".getBytes());
                                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer=ByteBuffer.wrap("1234\r\n".getBytes());
                                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread2.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
        
    //文件内容    
    abcd
    1234
    1234
    abcd
    ..省略
    

    2 write(ByteBuffer buffer,long position)

    从给定缓冲区读取能数据(limit-position),从函数设置position位置写入。

    • position > file.size 写入position之前位置补空位。
    • 通道中position伴随写入不移动
    • 多线程同步

    写入数据案例

    @Test
        public void test_write3() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write7.txt", "rw");
            RandomAccessFile writeFile = new RandomAccessFile("write7.txt", "rw");
            FileChannel fileChannel = writeFile.getChannel();
            FileChannel fileChannel2 = readFile.getChannel();
            try{
                /** 写入文件字节缓冲区数据 **/
                ByteBuffer buffer=ByteBuffer.wrap("--abcd".getBytes());
                buffer.position(2);
    
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                /** 将缓冲区中position->limist 数据从通道position位置写入 **/
                System.out.println ("write() size= " + fileChannel.write(buffer,0)) ;
                /** 写入文件之后的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
    
                System.out.println();
                /** 重置缓冲区 **/
                buffer.position(2);
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                /** 将缓冲区中position->limist 数据从通道position位置写入 **/
                System.out.println ("write() size= " + fileChannel.write(buffer,4)) ;
                /** 写入文件之后的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
    
                ByteBuffer allocate = ByteBuffer.allocate(8);
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
    
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    fileChannel.position= 0
    write() size= 4
    fileChannel.position= 0
    
    fileChannel.position= 0
    write() size= 4
    fileChannel.position= 0
    abcdabcd    
    

    多线程同步案例

    @Test
        public void test_write4() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write8.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                IntStream.range(0,10).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer=ByteBuffer.wrap("abcd".getBytes());
                                System.out.println(fileChannel.position());
                                System.out.println ("write() size= " + fileChannel.write(buffer,fileChannel.position())) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer=ByteBuffer.wrap("1234".getBytes());
                                System.out.println(fileChannel.position());
                                System.out.println ("write() size= " + fileChannel.write(buffer,fileChannel.position())) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread2.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
    
    //文件内容
    abcd or 1234 //位置每次从0开始 下一次覆盖上一次
    

    3 read(ByteBuffer buffer)

    读取案例

    从通道指定位置position读取通道数据(大小由缓冲区容量决定limit-position),写入到给定的缓冲区中

    • position > fileChannel.size 相当于不写入。
    • 通道中position伴随写入而移动。
    • 多线程同步
        @Test
        public void test_read() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write1.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            /** 从通道指定位置读取 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer=ByteBuffer.allocate(5);
                /** 从缓冲区指定位置写入 **/
                buffer.position(1);
                /** 从缓冲区写入限制位置 **/
                buffer.limit(5);
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                /** 从通道position位置开始读取buffer.remaining大小字节,从缓冲区position位置开始写入 **/
                System.out.println ("A fileChannel.readLength= " + fileChannel.read(buffer)) ;
                /** 写入文件之后的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                System.out.println (buffer) ;
                System.out.println (new String(buffer.array())) ;
                buffer.clear();
                System.out.println ("A fileChannel.readLength= " + fileChannel.read(buffer)) ;
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    fileChannel.position= 0
    A fileChannel.readLength= 2
    fileChannel.position= 2
    java.nio.HeapByteBuffer[pos=3 lim=5 cap=5]
     bb  
    A fileChannel.readLength= -1   
    

    多线程同步案例

    读取文件内容

    read.txt
    aaaalaaaa2aaaa3aaaa4aaaa5aaaa6aaaa7aaaa8aaaa9bbbblbbbb2bbbb3bbbb4bbbb5bbbb6bbbb7bbbb8bbbb9cccclcccc2cccc3cccc4cccc5cccc6cccc7cccc8cccc9
    
    @Test
        public void test_read2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("read.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                IntStream.range(0,3).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer=ByteBuffer.allocate(5);
                                int readLength = fileChannel.read(buffer);
                                while (readLength!=-1){
                                    System.out.println(new String(buffer.array(),0,readLength));
                                    buffer.clear();
                                    readLength = fileChannel.read(buffer);
                                }
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
        
    aaaal
    aaaa2
    aaaa3
    aaaa4
    aaaa5
    aaaa7
    ..省略
    

    4 read(ByteBuffer buffer,Long position)

    从函数指定位置position读取通道数据(大小由缓冲区容量决定limit-position),写入到给定的缓冲区中。

    • position > fileChannel.size 相当于不写入。
    • 通道中position伴随写入不移动
    • 多线程同步

    读取案例

    @Test
        public void test_read3() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write7.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                ByteBuffer buffer=ByteBuffer.allocate(5);
                buffer.position(1);
                buffer.limit(5);
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                /** 从通道position位置开始读取buffer.remaining大小字节,从缓冲区position位置开始写入 **/
                System.out.println ("A fileChannel.readLength= " + fileChannel.read(buffer,4)) ;
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
                System.out.println (buffer) ;
                System.out.println (new String(buffer.array())) ;
    
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    fileChannel.position= 0
    A fileChannel.readLength= 4
    fileChannel.position= 0
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
     abcd    
    

    5 write(ByteBuffer[] srcs)

    从给定缓冲区数组读取数据(总大小为每个缓冲区数据limit-position之和),从通道指定位置positio写入,

    • position > file.size 写入position之前位置补空位。
    • 通道中position伴随写入而移动。
    • 多线程同步

    写入案例

     @Test
        public void test_batchwrite() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write3.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            RandomAccessFile writeFile = new RandomAccessFile("write3.txt", "rw");
            FileChannel fileChannel2 = writeFile.getChannel();
            /** 从通道指定位置写入 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer1=ByteBuffer.wrap("000001".getBytes());
                ByteBuffer buffer2=ByteBuffer.wrap("000002".getBytes());
                buffer1.position(2);
                buffer1.limit(6);
                buffer2.position(2);
                buffer2.limit(6);
    
                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
                /** 将缓冲区数组中 每个缓冲区中position->limist 数据写入到文件设置position位置 **/
                Long writeLen = fileChannel.write(buffers);
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
    
                ByteBuffer allocate = ByteBuffer.allocate(writeLen.intValue());
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    A fileChannel.position ()= 0
    A fileChannel.position ()= 8
    00010002    
    

    线程同步案例

    @Test
        public void test_batchwrite2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write4.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            fileChannel.position(0);
            try{
                IntStream.range(0,10).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.wrap("00001\r\n".getBytes());
                                ByteBuffer buffer2=ByteBuffer.wrap("00002\r\n".getBytes());
                                buffer1.position(2);
                                buffer2.position(2);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                System.out.println ("write() size= " + fileChannel.write(buffers)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.wrap("0000a\r\n".getBytes());
                                ByteBuffer buffer2=ByteBuffer.wrap("0000b\r\n".getBytes());
                                buffer1.position(2);
                                buffer2.position(2);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                System.out.println ("write() size= " + fileChannel.write(buffers)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread2.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
    
    001
    002
    00a
    00b
    ...省略
    

    6 write(ByteBuffer[] srcs, int offset, int length)

    从给定缓冲区数组子序列读取数据(每个缓冲区写入数据=limit-position),从通道指定位置写入

    @param  srcs 写入通道字节缓冲区数组
    
    @param  offset 在缓冲区数组从哪个位置上缓冲区开始读取
         
    @param  length 从offset开始,读取多少个缓冲区
         
    @return  通道写入的字节数
    
    • position > file.size 写入position之前位置补空位。
    • 通道中position伴随写入而移动。
    • 多线程同步

    写入案例

    @Test
        public void test_batchwrite3() throws Exception {
    
            RandomAccessFile readFile = new RandomAccessFile("write5.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            RandomAccessFile writeFile = new RandomAccessFile("write5.txt", "rw");
            FileChannel fileChannel2 = writeFile.getChannel();
            /** 从文件指定位置写入 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer1=ByteBuffer.wrap("abcd".getBytes());
                ByteBuffer buffer2=ByteBuffer.wrap("-1234x".getBytes());
                buffer2.position(1);
                buffer2.limit(5);
                ByteBuffer buffer3=ByteBuffer.wrap("5678".getBytes());
                ByteBuffer buffer4=ByteBuffer.wrap("efch".getBytes());
    
                /** 将缓冲区数组中 每个缓冲区中position->limist 数据写入到文件设置position位置 **/
                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2,buffer3,buffer4};
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
                Long writeLen = fileChannel.write(buffers,1,3);
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
    
                ByteBuffer allocate = ByteBuffer.allocate(writeLen.intValue());
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    A fileChannel.position ()= 0
    A fileChannel.position ()= 12
    12345678efch    
    

    线程同步案例

     public static ByteBuffer[] getByteBufferArray(String str1,String str2){
            ByteBuffer buffer1=ByteBuffer.wrap(str1.getBytes());
            ByteBuffer buffer2=ByteBuffer.wrap(str2.getBytes());
            ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
            return  buffers;
        }
    
        @Test
        public void test_batchwrite4() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write6.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            fileChannel.position(0);
            try{
                IntStream.range(0,10).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer[] buffers=getByteBufferArray("aaaa","bbbb");
                                System.out.println ("write() size= " + fileChannel.write(buffers,0,2)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer[] buffers=getByteBufferArray("xxxx","yyyy");
                                System.out.println ("write() size= " + fileChannel.write(buffers,0,2)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread2.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
        
    aaaabbbbaaaabbbbxxxxyyyyaaaabbbbaaaabbbbxxxxyyyyxxxxyyyyaaaabbbbxxxxyyyyxxxxyyyyaaaabbbbaaaabbbbxxxxyyyyxxxxyyyyaaaabbbbxxxxyyyyxxxxyyyyaaaabbbbaaaabbbbxxxxyyyy    
    

    7 write(ByteBuffer[] dsts)

    从给定缓冲区数组读取数据(每个缓冲区写入数据=limit-position),从通道指定位置写入,通道中position偏移,多线程同步

    • position > file.size 写入position之前位置补空位。
    • 通道中position伴随写入而移动。
    • 多线程同步

    写入案例

     @Test
        public void test_batchwrite() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write3.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            RandomAccessFile writeFile = new RandomAccessFile("write3.txt", "rw");
            FileChannel fileChannel2 = writeFile.getChannel();
            /** 从通道指定位置写入 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer1=ByteBuffer.wrap("000001".getBytes());
                ByteBuffer buffer2=ByteBuffer.wrap("000002".getBytes());
                buffer1.position(2);
                buffer1.limit(6);
                buffer2.position(2);
                buffer2.limit(6);
    
                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
                /** 将缓冲区数组中 每个缓冲区中position->limist 数据写入到文件设置position位置 **/
                Long writeLen = fileChannel.write(buffers);
                System.out.println ("A fileChannel.position ()= " + fileChannel.position());
    
                ByteBuffer allocate = ByteBuffer.allocate(writeLen.intValue());
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    A fileChannel.position ()= 0
    A fileChannel.position ()= 8
    00010002    
    

    多线程同步案例

     @Test
        public void test_batchwrite2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write4.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            fileChannel.position(0);
            try{
                IntStream.range(0,10).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.wrap("00001\r\n".getBytes());
                                ByteBuffer buffer2=ByteBuffer.wrap("00002\r\n".getBytes());
                                buffer1.position(2);
                                buffer2.position(2);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                System.out.println ("write() size= " + fileChannel.write(buffers)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.wrap("0000a\r\n".getBytes());
                                ByteBuffer buffer2=ByteBuffer.wrap("0000b\r\n".getBytes());
                                buffer1.position(2);
                                buffer2.position(2);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                System.out.println ("write() size= " + fileChannel.write(buffers)) ;
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread2.start();
                });
            }finally {
    
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
    
    文件内容
    001
    002
    00a
    00b
    00a
    

    8 read(ByteBuffer[] dsts)

    将此通道指定position位置读取数据,写入字节缓冲区数组中(写入大小等于每个缓冲区容量(limit-position)之和)

    • position > fileChannel.size 相当于不写入。
    • 通道中position伴随写入而移动。
    • 多线程同步

    读取案例

    @Test
        public void test_batchread() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write3.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            /** 从通道指定位置读取 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer1=ByteBuffer.allocate(5);
                ByteBuffer buffer2=ByteBuffer.allocate(5);
                /** 从缓冲区指定位置写入 **/
                buffer1.position(1);
                /** 从缓冲区指定位置写入 **/
                buffer2.position(1);
                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
    
                /** 写入文件之前的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                System.out.println ("A fileChannel.read= " +  fileChannel.read(buffers));
                /** 写入文件之后的fileChannel.position()位置 **/
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
                System.out.println(buffer1);
                System.out.println(new String(buffer1.array()));
                System.out.println(buffer2);
                System.out.println(new String(buffer2.array()));
                buffer1.clear();
                buffer2.clear();
    
                System.out.println ("A fileChannel.read= " +  fileChannel.read(buffers));
    
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    fileChannel.position= 0
    A fileChannel.read= 8
    fileChannel.position= 8
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
     0001
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
     0002
    A fileChannel.read= -1    
    

    线程同步案例

    001/r/n
    002/r/n
    一行5个字节
    
    @Test
        public void test_batchread2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write4.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                IntStream.range(0,5).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.allocate(5);
                                ByteBuffer buffer2=ByteBuffer.allocate(5);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                long readLength = fileChannel.read(buffers);
                                while (readLength!=-1){
                                    synchronized (ReadAndWriteMethodTest.class ){
                                        for (int i = 0; i < buffers.length; i++) {
                                            System.out.println(new String(buffers[i].array()));
                                        }
    
                                    }
                                    buffer1.clear();
                                    buffer2.clear();
                                    readLength = fileChannel.read(buffers);
                                }
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                });
            }finally {
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
    
    001
    
    002
    
    00a
        
    

    9 read(ByteBuffer[] dsts, int offset, int length)

         * @param  dsts
         *         要写入的缓冲区数组
         *
         * @param  offset
         *         在缓冲区数组从哪个位置上缓冲区开始写入
         *
         * @param  length
         *         从offset开始,写入多少个缓冲区
         *
         * @return 从通道读取的字节数
    

    将数据从此通道读取,写入到给定缓冲区数组子序列中(写入大小<=每个缓冲区容量(limit-position)之和)。

    • position > fileChannel.size 相当于不写入。
    • 通道中position伴随写入不移动。
    • 多线程同步

    读取案例

    文件内容

    12345678efch
    
     @Test
        public void test_batchread3() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write5.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            /** 从文件指定位置读取 **/
            fileChannel.position(0);
            try{
                ByteBuffer buffer0=ByteBuffer.allocate(5);
                ByteBuffer buffer1=ByteBuffer.allocate(5);
                ByteBuffer buffer2=ByteBuffer.allocate(5);
                ByteBuffer buffer3=ByteBuffer.allocate(5);
                /** 从缓冲区指定位置写入 **/
                buffer1.position(1);
                /** 从缓冲区指定位置写入 **/
                buffer2.position(1);
                /** 从缓冲区指定位置写入 **/
                buffer3.position(2);
                ByteBuffer[] buffers=new ByteBuffer[]{buffer0,buffer1,buffer2,buffer3};
    
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
                System.out.println ("A fileChannel.read= " +  fileChannel.read(buffers,1,3));
                System.out.println ("fileChannel.position= " + fileChannel.position()) ;
    
                System.out.println(buffer1);
                System.out.println(new String(buffer1.array()));
                System.out.println(buffer2);
                System.out.println(new String(buffer2.array()));
                System.out.println(buffer3);
                System.out.println(new String(buffer3.array()));
                buffer1.clear();
                buffer2.clear();
                buffer3.clear();
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    
    fileChannel.position= 0
    A fileChannel.read= 11
    fileChannel.position= 11
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
     1234
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
     5678
    java.nio.HeapByteBuffer[pos=5 lim=5 cap=5]
      efc    
    

    线程通同步案例

    @Test
        public void test_batchread4() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write6.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            try{
                IntStream.range(0,5).forEach(i->{
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                ByteBuffer buffer1=ByteBuffer.allocate(4);
                                ByteBuffer buffer2=ByteBuffer.allocate(4);
                                ByteBuffer[] buffers=new ByteBuffer[]{buffer1,buffer2};
                                long readLength = fileChannel.read(buffers,0,2);
                                while (readLength!=-1){
                                    synchronized (ReadAndWriteMethodTest.class ){
                                        for (int i = 0; i < buffers.length; i++) {
                                            System.out.println(new String(buffers[i].array()));
                                        }
    
                                    }
                                    buffer1.clear();
                                    buffer2.clear();
                                    readLength = fileChannel.read(buffers);
                                }
                            } catch (IOException e) {
                            }
                        }
                    });
                    thread.start();
                });
            }finally {
            }
            Thread.sleep(3000);
            readFile.close();
            fileChannel.close();
        }
    
    aaaa
    bbbb
    aaaa
    bbbb
    xxxx
    yyyy
    aaaa
    bbbb
    

    10 position(int newPosition)

    position 表示写入读取通道起始位置

    • write(ByteBuffer buffer),read(ByteBuffer buffer)操作时position会移动
    @Test
        public void test_position() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write9.txt", "rw");
            RandomAccessFile writeFile = new RandomAccessFile("write9.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            FileChannel fileChannel2 = writeFile.getChannel();
            try{
                /** 写入文件字节缓冲区数据 **/
                ByteBuffer buffer=ByteBuffer.wrap("--abcd".getBytes());
                buffer.position(2);
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                System.out.println(fileChannel.position());
                System.out.println(fileChannel.size());
                /** 重置缓冲区 **/
                buffer.position(2);
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer)) ;
                System.out.println(fileChannel.position());
                System.out.println(fileChannel.size());
    
                ByteBuffer allocate = ByteBuffer.allocate(8);
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
    
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    

    write(ByteBuffer buffer, long position),read(ByteBuffer buffer, long position)操作时position不会移动

    @Test
        public void test_position2() throws Exception {
            RandomAccessFile readFile = new RandomAccessFile("write10.txt", "rw");
            RandomAccessFile writeFile = new RandomAccessFile("write10.txt", "rw");
            FileChannel fileChannel = readFile.getChannel();
            FileChannel fileChannel2 = writeFile.getChannel();
            try{
                /** 写入文件字节缓冲区数据 **/
                ByteBuffer buffer=ByteBuffer.wrap("--abcd".getBytes());
                buffer.position(2);
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer,fileChannel.position())) ;
                System.out.println(fileChannel.position());
                System.out.println(fileChannel.size());
                /** 重置缓冲区 **/
                buffer.position(2);
                /** 将缓冲区中position->limist 数据写入到文件设置position位置 **/
                System.out.println ("write() size= " + fileChannel.write(buffer,fileChannel.position())) ;
                System.out.println(fileChannel.position());
                System.out.println(fileChannel.size());
    
                ByteBuffer allocate = ByteBuffer.allocate(8);
                fileChannel2.read(allocate);
                System.out.println(new String(allocate.array()));
    
            }finally {
                readFile.close();
                fileChannel.close();
            }
        }
    

    11 force(boolean metaData)

    让缓冲区的数据写入磁盘时,如果metaData传人值为true ,则需要将文件元数据进行更改也写入磁盘

    @Test
        public void test_force() throws Exception {
            RandomAccessFile writeFile = new RandomAccessFile("write12.txt", "rw");
            FileChannel fileChannel = writeFile.getChannel();
            try{
                /** 写入文件字节缓冲区数据 **/
                ByteBuffer buffer=ByteBuffer.wrap("1111111111".getBytes());
                long begin = System.currentTimeMillis();
                for (int i=0;i<=5000;i++){
                    fileChannel.write(buffer);
                    fileChannel.force(true);
                    buffer.clear();
                }
                long end = System.currentTimeMillis();
                System.out.println(end-begin);
    
    
                ByteBuffer buffer1=ByteBuffer.wrap("22222222222".getBytes());
                begin = System.currentTimeMillis();
                for (int i=0;i<=5000;i++){
                    fileChannel.write(buffer1);
                    buffer1.clear();
                }
                end = System.currentTimeMillis();
                System.out.println(end-begin);
    
    
            }finally {
                writeFile.close();
                fileChannel.close();
            }
        }
    

    相关文章

      网友评论

          本文标题:JavaNIO-通道02 FileChannel 文件操作

          本文链接:https://www.haomeiwen.com/subject/oqiclctx.html