JAVA NIO FileChannel 内存映射文件
发布日期:2021-05-09 05:38:09 浏览次数:41 分类:博客文章

本文共 12606 字,大约阅读时间需要 42 分钟。

 
 

 

文件通道总是阻塞式的。

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

线程安全。

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

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();        }    }}

 

上一篇:JAVA NIO Socket通道
下一篇:JAVA NIO Scatter/Gather(矢量IO)

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年04月16日 08时31分45秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章