内存映射文件
一、内存映射文件
内存映射文件的优势是比其他操作文件的方法访问文件的速度要快。
方法:
1)获得一个通道
FileChannel channel = FileChannel.open(path,options);
还能通过在一个打开的 File 对象(RandomAccessFile、FileInputStream 或 FileOutputStream)上调用 getChannel() 方法获取。调用 getChannel() 方法会返回一个连接到相同文件的 FileChannel 对象且该 FileChannel 对象具有与 File 对象相同的访问权限。
2)调用FileChannel类的map方法从这个通道中获得一个ByteBuffer缓冲区,并且可以指定缓冲区的模式
调用 MappedByteBuffer map (FileChannel.MapMode mode, long position, long size);
position :起始位置
size:大小
mode的取值:
FileChannel.MapMode.READ_ONLY 只读缓冲区
FileChannel.MapMode.READ_WRITE 文件可写,但是不同步
FileChannel.MapMode.PRIVATE 缓冲区是可以修改的,但是不能将修改后的内容写到文件中
二、缓冲区数据结构
1)一个容量,缓冲区的容量是不变的
2)一个读写位置,下一个要进行操作的位置
3)缓冲区中有一个存储界限,这是数据的边界
4)一个可选标记,用于重复操作
0 <= 标记 <= 位置 <= 界限 <= 容量
对缓冲区的操作可以查看Java API java.nio.Buffer
三、文件加锁机制
当多个线程访问同一个文件的时候有可能造成文件数据的破坏,为了避免这种情况的发生,特定用一个锁来控制文件的访问
FileLock lock = channel.lock(); //锁定
FileLock lock = channel.tryLock(); //申请获得锁
lock.release(); //释放锁
还可以通过传参锁定缓冲区的一部分:
FileLock lock(long start, long size, boolean shared) 或 FileLock tryLock(long start, long size, boolean shared)
注意点:
1、文件加锁机制是依赖于操作系统的
2、意外的建议锁:在某些系统中文件锁仅仅是建议性的,可能出现一个应用未能得到锁,它仍旧可以向被另一个进程并发锁定的文件执行写操作;
3、意外的原子性:在某些系统中,不能在锁定一个文件的同时将其映射到内存中,原子性;
4、意外的全释放:在某些系统中,关闭一个通道会释放由JVM持有的底层文件上的所有锁,因此避免在同一个锁定文件上使用多个通道,不然其他通道的锁也可能被释放!
5、不可重入锁:文件锁是由整个JVM持有的,两个由同一VM启动的程序不可能获得在同一个文件上的锁,如果尝试对VM上已加锁的文件再加锁,将抛出OverlappingFileLockException;
(注意:多线程的ReentranLock是可重入的!简称可重入锁,而文件锁是不可重入锁)
6、在网络文件系统上锁定文件是高度依赖于系统的,尽量避免使用文件锁。