FileChannel和文件锁

FileChannel

FileChannel 可以通过 RandomAccessFile 获取,或者FileChannel.open,亦或 IS/OS 获取。write 和 read 都是通过 ByteBuffer 来存储。

FileChannel.open 时可以提供 OpenOption 来定义行为,如果需要写的话可以使用 write 和 append 模式,在不确定文件是否存在是加入 Create,这样如果不存在会自动创建。

write 和 append 有什么区别?

这两种模式声明的不是 FileChannel 的模式,而是声明那个文件的打开模式,作为 FileChannel 只顾自己position 增加,在 write 模式下文件的 postion 跟 Channel 的 position 是一致的,但是在 append 模式下文件 position 跟 Channel 的完全脱节,两者都是自顾自增加。

说到这里你可能已经想到,如果要实现每次输入内容覆盖之前的话,必须选择 Write 模式,并且每次 channel.write 前都需要将channel的 position 置为零。

文件锁 Lock

FileChannel.lock  和  tryLock  从文档上看一个是同步阻塞、另一个是非阻塞。

tryLock 在同一个JVM中不同线程获取时,先到先得,后到的返回null,但我在windows上测试为抛出异常:OverlappingFileLockException ,据说 Linux 上抛出【java.io.IOException:Permission denied】。

tryLock 和 lock 都提供一个API含有三个参数

lock(long position,
            long size,
            boolean shared)

看样子貌似可以锁住部分似的,可能跟操作系统有关,反正windows上并不行,抛出异常:

java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。

共享锁,独占锁概念上跟并发的 WriteReadLock 一样可多读但只一写,写是独占的。

怎么设置?看上面API第三个参数。

lock(long position,
            long size,
            boolean shared) // 是否共享锁

如何判断获取到的是什么锁?

FileLock.isShared()

实现靠谱的文件锁

主要就是一个循环判断加try.catch

       while (true) {
           try {
              lock = fc.lock();
              break;
           } catch (OverlappingFileLockException e) {
              Thread.sleep(1 * 1000);
           }
        }

这可以让需要获取锁的代码块阻塞在那里,当然咯,如果想 wait 也是可以的,只是要在 release 的地方加上 notifyAll 了。

内存映射文件

这个可谓 “大杀器”,特别是大文件读写时,效率比普通IO要快N倍。据一位网友测试86M的文件进行读操作,内存映射方式只要78ms,而普通IO需要468ms,差了6倍。可见威力无穷。

为什么这么快?

普通IO是操作系统先读入到内核缓冲器,再转到用户进程私有的内存区,当然JVM进程还作了内核态和用户态的切换;而内存映射方式,是将文件直接映射到内存中的一块区域,当调用读时会抛出缺页异常,OS会读取该页数据,依次往复,因此这里少了依次内核缓冲区到私有内存之间的拷贝,所以快了不少。

内存映射模式

  1. read_only,只读设置
  2. read_write,读写都可,并且任何写操作立即反应在文件上,其他共享该文件的内存映射也能立即看到
  3. private,私有模式,不写时跟read_only 一样,但是写时会克隆一个独立内存区域,不会影响文件。

代码片段

File file = new File("E:\\test.txt");  
FileInputStream in = new FileInputStream(file);  
FileChannel channel = in.getChannel();  
MappedByteBuffer mappedBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,channel.size());

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老马说编程

(61) 内存映射文件及其应用 - 实现一个简单的消息队列 / 计算机程序的思维逻辑

本节介绍内存映射文件,内存映射文件不是Java引入的概念,而是操作系统提供的一种功能,大部分操作系统都支持。 我们先来介绍内存映射文件的基本概念,它是什么,能解...

31350
来自专栏小狼的世界

PHP手册阅读笔记

学习PHP以来一直希望有时间能够有时间通读PHP手册,最近终于强迫自己划出一些时间,完成了对PHP手册的通读。除了函数参考部分没有每个都看,其他的章节基本上都看...

21740
来自专栏mini188

Openfire的启动过程与session管理

说明 本文源码基于Openfire4.0.2。 Openfire的启动     Openfire的启动过程非常的简单,通过一个入口初始化lib目录下的openf...

31380
来自专栏林冠宏的技术文章

java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍

(原创,转载请说明出处!谢谢--https://cloud.tencent.com/developer/user/1148436/activities)  此文...

20570
来自专栏别先生

JSch - Java实现的SFTP(文件上传详解篇)

  JSch是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。它允许你连接到一个SSH服务器,并且可以使用端口转发,X11...

1.5K10
来自专栏Android 开发学习

Android内存泄漏分析总结

21240
来自专栏圆方圆学院精选

【刘文彬】 Debug EOS:nodeos + mongo_db_plugin

原文链接:醒者呆的博客园,https://www.cnblogs.com/Evsward/p/storage.html

17320
来自专栏一个会写诗的程序员的博客

《Kotin 极简教程》第9章 轻量级线程:协程(2)《Kotlin极简教程》正式上架:

如果需要依次调用它们, 我们只需要使用正常的顺序调用, 因为协同中的代码 (就像在常规代码中一样) 是默认的顺序执行。下面的示例通过测量执行两个挂起函数所需的总...

16120
来自专栏大内老A

Self Host模式下的ASP. NET Web API是如何进行请求的监听与处理的?

构成ASP.NET Web API核心框架的消息处理管道既不关心请求消息来源于何处,也不需要考虑响应消息归于何方。当我们采用Web Host模式将一个ASP.N...

34950
来自专栏博岩Java大讲堂

Java-SPI机制

27940

扫码关注云+社区

领取腾讯云代金券