前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA NIO FileChannel 内存映射文件

JAVA NIO FileChannel 内存映射文件

作者头像
WindWant
发布2020-09-11 10:56:25
1.5K0
发布2020-09-11 10:56:25
举报
文章被收录于专栏:后端码事

文件通道总是阻塞式的。

文件通道不能创建,只能通过(RandomAccessFile、FileInputStream、FileOutputStream)getChannel()获得,具有与File形同的访问权限。

线程安全。

文件锁:锁的对象是文件。

代码语言:javascript
复制
package org.windwant.nio;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.Selector;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by windwant on 2016/5/13.
 */
public class NIOOpt {

    public static void main(String[] args) {
        try {
            MappedPrivateChannel();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * MapMode.PRIVATE 写时拷贝(copy-on-write)映射:通过put()修改的任何修改,会导致产生一个私有的数据
     * 拷贝,宝贝中的数据只有MappedByteBuffer实例可以看到。不会对底层文件做任何修改。若缓冲区被回收,修改丢
     * 失,read/write方式建立通道。
     * 做修改,拷贝副本前,其它方式的映射区的修改,会反映到当前区域。映射相互的修改不可见
     * 允许父子进程共享内存页
     * 处理一个文件多个映射场景。
     * 关闭通道,映射会保持。除非丢弃缓冲区本身。
     * MappedByteBuffer 对象是直接的,占用的内存位于jvm堆栈之外。
     */
    public static void MappedPrivateChannel() throws Exception {
        // Create a temp file and get a channel connected to it
        File tempFile = File.createTempFile ("mmaptest", null);
        RandomAccessFile file = new RandomAccessFile (tempFile, "rw");
        FileChannel channel = file.getChannel( );
        ByteBuffer temp = ByteBuffer.allocate (100);
        // Put something in the file, starting at location 0
        temp.put ("This is the file content".getBytes( ));
        temp.flip( );
        channel.write (temp, 0);
        // Put something else in the file, starting at location 8192.
        // 8192 is 8 KB, almost certainly a different memory/FS page.
        // This may cause a file hole, depending on the
        // filesystem page size.
        temp.clear( );
        temp.put ("This is more file content".getBytes( ));
        temp.flip( );
        channel.write (temp, 8192);
        // Create three types of mappings to the same file
        MappedByteBuffer ro = channel.map (
                FileChannel.MapMode.READ_ONLY, 0, channel.size( ));
        MappedByteBuffer rw = channel.map (
                FileChannel.MapMode.READ_WRITE, 0, channel.size( ));
        MappedByteBuffer cow = channel.map (
                FileChannel.MapMode.PRIVATE, 0, channel.size( ));
        // the buffer states before any modifications
        System.out.println ("Begin");
        showBuffers (ro, rw, cow);
        // Modify the copy-on-write buffer
        cow.position (8);
        cow.put ("COW".getBytes( ));
        System.out.println ("Change to COW buffer");
        showBuffers (ro, rw, cow);
        // Modify the read/write buffer92
        rw.position (9);
        rw.put (" R/W ".getBytes( ));
        rw.position (8194);
        rw.put (" R/W ".getBytes( ));
        rw.force( );
        System.out.println ("Change to R/W buffer");
        showBuffers (ro, rw, cow);
        // Write to the file through the channel; hit both pages
        temp.clear( );
        temp.put ("Channel write ".getBytes( ));
        temp.flip( );
        channel.write (temp, 0);
        temp.rewind( );
        channel.write (temp, 8202);
        System.out.println ("Write on channel");
        showBuffers (ro, rw, cow);
        // Modify the copy-on-write buffer again
        cow.position (8207);
        cow.put (" COW2 ".getBytes( ));
        System.out.println ("Second change to COW buffer");
        showBuffers (ro, rw, cow);
        // Modify the read/write buffer
        rw.position (0);
        rw.put (" R/W2 ".getBytes( ));
        rw.position (8210);
        rw.put (" R/W2 ".getBytes( ));
        rw.force( );
        System.out.println ("Second change to R/W buffer");
        showBuffers (ro, rw, cow);
        // cleanup
        channel.close( );
        file.close( );
        tempFile.delete( );
    }

    // Show the current content of the three buffers
    public static void showBuffers (ByteBuffer ro, ByteBuffer rw, ByteBuffer cow) throws Exception{
        dumpBuffer ("R/O", ro);
        dumpBuffer ("R/W", rw);
        dumpBuffer ("COW", cow);
        System.out.println ("");
    }
    // Dump buffer content, counting and skipping nulls
    public static void dumpBuffer (String prefix, ByteBuffer buffer) throws Exception {
        System.out.print (prefix + ": '");
        int nulls = 0;
        int limit = buffer.limit( );
        for (int i = 0; i < limit; i++) {
            char c = (char) buffer.get (i);
            if (c == '\u0000') {
                nulls++;
                continue;
            }
            if (nulls != 0) {
                System.out.print ("|[" + nulls
                        + " nulls]|");
                nulls = 0;
            }
            System.out.print (c);
        }
        System.out.println ("'");
    }

    /**
     * channel Gather/Scatter 矢量IO
     */
    public static void channelGatherScatter(){
        ByteBuffer head = ByteBuffer.allocate(4);
        ByteBuffer body = ByteBuffer.allocate(100);
        RandomAccessFile afile = null;
        RandomAccessFile bfile = null;
        ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        try {
            afile = new RandomAccessFile("hello.txt", "r");
            bfile = new RandomAccessFile("hehe.txt", "rw");
            readWriteLock.readLock().lock();
            FileChannel fileChannel = afile.getChannel();
            ByteBuffer[] buffers = {head, body};
            while (fileChannel.read(buffers) != -1){
            }
            head.flip();
            body.flip();
            System.out.println(new String(head.array()));
            System.out.println(new String(body.array()));
            readWriteLock.readLock().unlock();
            fileChannel.close();
            afile.close();

            readWriteLock.writeLock().lock();
            FileChannel bfileChannel = bfile.getChannel();

            while (bfileChannel.write(buffers) > 0){
            }

            bfileChannel.position(bfileChannel.position() + 10);
            bfileChannel.write(ByteBuffer.wrap("THIS IS THE TEST TEXT!".getBytes()));
            bfileChannel.truncate(3); //改变文件大小
            bfileChannel.force(true); //写入磁盘文件 参数 是否更新文件元数据(所有者、访问权限等)
            readWriteLock.writeLock().unlock();
            bfileChannel.close();
            bfile.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 基于MappedFileChannle的文件复制
     * 文件锁
     */
    public static void mappedFileChannelLock(){
        RandomAccessFile afile = null;
        RandomAccessFile bfile = null;
        FileChannel fc = null;
        FileChannel fcb = null;
        try {
            afile = new RandomAccessFile("hello.txt", "rw");
            fc = afile.getChannel();
            long length = fc.size();
            FileLock fileLock = fc.tryLock(0, length, true);//true共享锁 false 独占锁 从开始 锁定全部内容 如果获取不到锁会返回null
            if(null != fileLock) {
                MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
                byte[] fbo = new byte[(int) length];
                mbb.get(fbo);
                System.out.println(new String(fbo, "UTF-8"));
                fileLock.release();
                bfile = new RandomAccessFile("hehe.txt", "rw");
                fcb = bfile.getChannel();
                fileLock = fcb.tryLock(0, length, false);
                MappedByteBuffer mbbb = fcb.map(FileChannel.MapMode.READ_WRITE, 0, length);

                for (int i = 0; i < length; i++) {
                    mbbb.put(i, fbo[i]);
                }
                mbbb.flip();
                mbbb.force();
                fileLock.release();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fc.close();
                fcb.close();
                afile.close();
                bfile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * MappedByteBuffer map(MapMode mode, long position, long size)
     * size大于文件大小,文件会做扩充
     * MappedByteBuffer 内存映射缓冲池
     * 基于MappedFileChannle的文件复制
     * 读写锁
     * 直接读取,修改磁盘上的文件。
     * 自动缓存内存页,比较高效。
     */
    public static void mappedFileChannel(){
        RandomAccessFile afile = null;
        RandomAccessFile bfile = null;
        FileChannel fc = null;
        FileChannel fcb = null;
        ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        try {
            afile = new RandomAccessFile("hello.txt", "rw");
            readWriteLock.readLock().lock();
            fc = afile.getChannel();
            long length = fc.size();
            MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
            byte[] fbo = new byte[(int) length];
            mbb.get(fbo);
            System.out.println(new String(fbo));
            readWriteLock.readLock().unlock();
            bfile = new RandomAccessFile("hehe.txt", "rw");
            readWriteLock.writeLock().lock();
            fcb = bfile.getChannel();
            MappedByteBuffer mbbb = fcb.map(FileChannel.MapMode.READ_WRITE, 0, length);

            for (int i = 0; i < length; i++) {
                mbbb.put(i, fbo[i]);
            }
            mbbb.flip();
            mbbb.force();
            readWriteLock.writeLock().unlock();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fc.close();
                fcb.close();
                afile.close();
                bfile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * FileChannel文件读取
     */
    public static void fileChannel(){
        try {
            RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
            FileChannel fc = afile.getChannel();
            ByteBuffer bb = ByteBuffer.allocate(48);
            int byteRead;
            while ((byteRead = fc.read(bb)) != -1){//确保读完
                System.out.println("read:" + byteRead);
                bb.flip();//翻转为读状态
                while (bb.hasRemaining()){//直到没有可读的字节
                    System.out.println(String.valueOf(bb.get()));
                }
                bb.clear();
            }
            fc.close();
            afile.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 基于FileChannel transferTo transferFrom 方法文件复制
     */
    public static void fileTransfer(){
        try {
            RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
            RandomAccessFile bfile = new RandomAccessFile("hehe.txt", "rw");
            FileChannel ac = afile.getChannel();
            FileChannel bc = bfile.getChannel();
            long position = 0;
            long count = ac.size();
//            bc.transferFrom(ac, position, count);
            ac.transferTo(position, count, bc);
            ac.close();
            afile.close();
            bc.close();
            bfile.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void fileSelector(){
        try {
            RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
            Channel c = afile.getChannel();
            Selector s = Selector.open();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 基于基本channel buffer的文件复制操作
     */
    public static void fileTransferByNormal() {
        try {
            RandomAccessFile afile = new RandomAccessFile("hello.txt", "rw");
            RandomAccessFile bfile = new RandomAccessFile("hehe.txt", "rw");
            FileChannel ac = afile.getChannel();
            FileChannel bc = bfile.getChannel();

            ByteBuffer bf = ByteBuffer.allocateDirect(16 * 1024);
            while (ac.read(bf) != -1) {
                bf.flip();
                while (bf.hasRemaining()) {//确保写完
                    bc.write(bf);
                }
                bf.clear();
            }
            ac.close();
            afile.close();
            bc.close();
            bfile.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-10-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档