FileChannel阅读笔记
文章目录
一、简介
主要作用是读取、写入、映射和操作文件的通道。该通道永远是阻塞的操作,内部维护了一个当前文件的position。该文件本身包含一个可读写、长度可变的字节序列,并且可以查询该文件的当前大小。
二、继承关系图
- ByteChannel:具有可读写字节的通道(继承的WriteableChannel和ReadByteChannel)
- SeekableByteChannal:可以维护通道的position和允许position发生改变
- AbstractInterruptibleChannel:提供一个可被中断的通道
三、存储结构
无
四、源码分析
内部类
- MapMode 就是用于映射文件采用什么模型,读、读写、专用三种
属性
- 字段不用介绍了
构造
- 就一个受保护的无参构造器
主要方法
1、write方法
具有同步,遵循mark、position、limit、capacity
public abstract int write(ByteBuffer src) throws IOException;
- 写操作,将remaining字节从给定的缓冲区写入此通道的当前位置。
public abstract long write(ByteBuffer[] srcs, int offset, int length)throws IOException;
- 批量部分写操作,以指定缓冲区数组的offset下标开始,向后使用length个字节缓冲区,再将每个缓冲区的remaining剩余字节子序列写入此通道的当前位置
public final long write(ByteBuffer[] srcs) throws IOException
- 批量写操作,将每个缓冲区的remaining字节序列写入到此通道的当前位置,调用的就是上面的方法。
public abstract int write(ByteBuffer src, long position) throws IOException;
- 向通道的指定位置写入数据,将缓冲区的remaining剩余字节序列写入到通道的指定位置。此操作不用影响通道原有的position值。
2、read方法
具有同步,遵循mark、position、limit、capacity
读取返回结果就是本次读取的字节数量。如果是 -1 说明没有数据读取出来
public abstract int read(ByteBuffer dst) throws IOException;
- 写操作,将字节序列从此通道的当前位置读入给定的缓冲区的当前位置。
public abstract long read(ByteBuffer[] dsts, int offset, int length)throws IOException;
- 批量部分读操作,将通道当前位置的字节序列读入以数组下标为offset开始的ByteBuffer[]数组中的remaining剩余空间中,并且连续写入length个ByteBuffer缓冲区。
public final long read(ByteBuffer[] dsts) throws IOException
- 批量读操作,将字节序列从此通道读入给定的缓冲区数组中的第0个缓冲区的当前位置
public abstract int read(ByteBuffer dst, long position) throws IOException;
- 读取通道指定位置的数据将通道指定位置的字节序列读入给定的缓冲区的当前位置。
3、position方法
public abstract FileChannel position(long newPosition) throws IOException;
- 设置此通道的文件位置。
- 将该位置设置为大于文件当前大小的值是合法的,但这不会更改文件大小,
- 稍后试图在这样的位置读取字节序列将返回已到达文件末尾的指示(-1)
- 稍后试图在这样的位置写入字节序列将导致文件扩大,以容纳新的字节,在以前文件末尾和新写入字节之间的字节值是未指定的。
4、truncate方法
public abstract FileChannel truncate(long size) throws IOException;
- 将此通道的文件截取为给定大小。
- 如果给定大小小于该文件的当前大小,则截取该文件,丢弃未见新末尾后面的所有字节。
- 如果给定大小大于或等于该文件的当前大小,则不修改文件。
- 无论是哪种情况,如果此通道的文件位置大于给定大小,则将位置设置为该大小。
- 将此通道的文件截取为给定大小。
5、transferTo方法
public abstract long transferTo(long position, long count,WritableByteChannel target)throws IOException;
- 将数据传输到其他可写入字节通道
- 其实和write一样,只不过是将通道中的数据传输到另一个通道中,而不是缓冲区中
- 从自己通道指定的position开始读取count个字节,写入到指定的target字节通道的当前位置
- 如果给定的位置大于该文件的当前大小,则不传输任何字节。
- 如果count大于position到size的字节个数则会只传输sizie-positin个字节
6、tranferForm方法
public abstract long transferFrom(ReadableByteChannel src,long position, long count)throws IOException;
- 将字节从给定可读取字节通道传输到此通道的文件中
- 此方法不会修改通道的position
- src 源通道
- position 从自己的position开始接受src读取出来的数据
- count 要接受的最大字节数,
- 将字节从给定可读取字节通道传输到此通道的文件中
7、lock方法
public abstract FileLock lock(long position, long size, boolean shared)throws IOException;
- 获取此通道的文件给定区域的锁定
- 会阻塞
- 在锁定该区域之前、已关闭此通道之前或者已中断调用线程之前(以先到者为准),将紫塞此方法的调用
- 在此方法调用期间,如果另一个 线程关闭了此通道,则抛出AsynchronousCloseException异常
- 文件的扩大和缩小不会影响锁定的范围
- position锁定的开始位置
- size 锁定的大小
- shared true为共享锁,false为独占锁
- 共享锁,自己能读,不能写,别人能读、不能写
- 独占锁,自己能读、能写,别人不能读、不能写
- 获取此通道的文件给定区域的锁定
public final FileLock lock() throws IOException
return lock(0L, Long.MAX_VALUE, false);
内部就是调用的上面,用的Long.MAX_VALUE- 所以不做说明。就是开启了独占锁从0开始到Long.MAX_VALUE的最大值
8、tryLock方法
public abstract FileLock tryLock(long position, long size, boolean shared)throws IOException;
- 获取通道文件给定区域的锁定
- 不会阻塞
- 如果由于其他程序保持着一个重叠锁定而无法获取锁,返回null
- 如果由于任何其他原因无法获取锁定,则抛出相应的异常
- 某些操作系统不支持共享锁定,在这种情况下,自动将对共享锁定的请求转换为对独占锁定的请求,可以通过调用锁定对象的siShard()的方法来测试获新获取的锁定是共享锁还是独占锁
- 获取通道文件给定区域的锁定
public final FileLock tryLock() throws IOException
return tryLock(0L, Long.MAX_VALUE, false);
内部就是调用的上面,用的Long.MAX_VALUE- 所以不做说明,就是尝试用独占锁从0开始到Long.MAX_VALUE的最大值锁定
9、force方法
public abstract void force(boolean metaData) throws IOException;
- 强制将所有对通道文件的更新写入包含文件的存储设备
- 操作系统为了运行的效率,先是把那些将要保存到硬盘上的数据暂时放入操作系统内核的缓冲区,以减少硬盘的读写次数,然后再某一个时间点再将内核缓存中的数据批量同步到硬盘中,但是同步的时间却是由操作系统决定的,因为时间是未知的,这时就不能让操作系统来决定,所以要显式的调用force(boolean)方法来强制执行同步
- 执行force方法是有运行效率成本的。
- 强制将所有对通道文件的更新写入包含文件的存储设备
10、map方法
public abstract MappedByteBuffer map(MapMode mode,long position, long size)throws IOException;
- 将通道文件区域直接映射到内存
FileChannel.MapMode.PRIVATE
- 专用:对于得到的缓冲区的更改不会传播到文件,并且该更改对映射到同以文件的其他程序是不可见的。但是会创建缓冲区已修改部分的专用副本。
FileChannel.MapMode.READ_ONLY
- 只读,试图修改得到的缓冲区将抛出ReadOnlyBufferException异常
FileChannel.MapMode.READ_WRITE
- 读取/写入:对得到的缓冲区修更改最终将传播到文件;
- 但是该更改对映射到同一个文件的其他程序不一定是可见的。
- 读取/写入:对得到的缓冲区修更改最终将传播到文件;
- position和size 就是映射的区域
- 将通道文件区域直接映射到内存
11、open
-
StandardOpenOption
用于打开指令-
READ 读, 打开以进行读取访问 WRITE 写, APPEND 追加, 如果打开文件以进行写入访问,则字节将写入文件末尾而不是开始 TRUNCATE_EXISTING 如果该文件已存在并且为写入访问而打开,则其长度将被截断为0. 如果文件为读取访问打开,则忽略 也就是用这样的方式打开后关闭,会清空文件 CREATE 创建, 单独使用CREATE常量不可以创建,需要结合WRITE CREATE_NEW 创建新的, 如果该文件存在,则失败抛异常,如果结合WRITE则不会抛异常 DELETE_ON_CLOSE 关闭时删除 SPARSE 稀疏文件, 与CREATE_NEW选项一起使用时,此选项提供了一个提示, 表明新文件讲是稀疏的。当文件系统不支持创建稀疏文件时,将忽略该选项。 因为,其他指令,也就是如果opsition是10000 处写入了a,那么就会占用10000的空间, 但是用SPARSE可以达到只占用a,这样可以有效利用空间 注意:不要使用CREATE来创建SPARSE文件,而是使用CREATE_NEW来创建稀疏文件 SYNC 同步, 要求对“文件内容或元数据”的每次更新都同步写入底层存储设备。这样做,程序效率降低 SYNC 同步, 要求对“文件内容”的每次更新都同步写入底层存储设备
-
12、isOpen
- 判断通道是否打开,打开返回true,没有返回false。
补充
1、FileLock类的API
- isShard() 如果返回true是共享锁,返回false是独占锁
- overlaps() 测试锁定范围是否与 现有锁定重叠,需要传入测试区域 position和size
- release() 释放锁
- channel() 返回当前锁所属的FileChannel文件通道对象
- acquireBy() 返回当前锁所属的FileChannel文件通道对象,最新的jdk中用于替代channel函数
2、MappedByteBuffer类
- 它是直接字节缓冲区,其内容是文件的内存映射区域,映射的字节缓冲区是通过FileChannel.map()方法创建的。此类用于特定于内存映射文件区域的操作扩展ByteBuffer类,这个映射关系会一直保持到该缓冲区本身成为垃圾之前
- force():将此缓冲区所做的内容更改强制写入包含映射文件的存储设备中,会影响效率
- isLoaded():判断此缓冲区的内容是否位于物理内存中
- 如果是true,说明是位于物理内存中,因此是可访问的,不会导致任何虚拟内存页错误
- load():将此缓冲区的内容加载到物理内存中
- 调用此方法可能 导致一些有页面错误,并导致发生I/O操作
五、总结
太懒了, 没什么总结的。