【0】README

0.1) 本文描述转自 core java volume 2, 旨在理解 java流与文件——内存映射文件 的相关知识;
0.2)内存映射文件的目的是: 提高访问速度, 缓冲区Buffer;
0.3) 本文干货源代码均为原创, for source code , please visit https://github.com/pacosonTang/core-java-volume/blob/master/coreJavaAdvanced/chapter1/MemoryMapTest.java


【1】intro to 内存映射文件

1.1)大多数os 都利用 虚拟内存实现来将 一个文件或文件的一部分映射到 内存中;
1.2)java.nio 包使内存映射变得简单, 下面是我们需要做的:

  • 1.2.1)首先,从文件中获得一个通道, 通道是对 磁盘文件的一种抽象, 它使我们可以访问诸如内存映射, 文件加锁机制以及文件间快速数据传递等操作系统特性;(干货——通道的定义,即对磁盘文件的抽象)
    FileChannel channel = FIleChannel.open(path , options);
  • 1.2.2) 然后, 调用FileChannel 类的map方法从这个通道中获得一个 ByteBuffer。 你可以指定想要映射的文件区域与映射模式, 支持的模式有三种(Model):
    • M1)FileChannel.MapMode.READ_ONLY: 所产生的缓冲区是只读的, 任何对该缓冲区写入都会产生异常;
    • M2)FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的;任何修改都会在这个时刻写回到文件中;
    • M3)FileChannel.MapMode.PRIVATE: 所产生的缓冲区是可写的, 但是任何修改对这个缓冲区来说都是私有的,不会传播到文件中;

1.3)一旦有了缓冲区,就可以使用 ByteBuffer 类 和 Buffer 超类的方法读写数据了;

  • 1.3.1)缓冲区支持顺序和随机数据访问, 它有一个可以通过get 和 put 操作来移动的位置;如, 像下面这样遍历缓冲区中的所有字节:
    while(buffer.hasRemaining)
    {
    byte b = buffer.get();
    }
  • 1.3.2)或者像下面这样进行随机访问:
    for(i=0;i
CRC32 crc = new CRC32();
while(more bytes)crc.update(next byte)
long checksum = crc.getValue();


【2】缓冲区数据结构

2.1)在使用内存映射时, 我们创建了单一的缓冲区横跨整个文件或我们感兴趣的文件区域。我们还可以使用更多的缓冲区来读写大小适度的信息块;
2.2)本节将简要介绍Buffer 对象上的基本操作。

  • 2.2.1)缓冲区定义:缓冲区是由具有相同类型的数值构成的数组,Buffer 类是一个抽象类, 它有众多的具体子类,包括ByteBuffer, CharBuffer, DoubleBuffer, IntBuffer, LongBuffer, ShortBuffer ; (干货——缓冲区定义)
    Attention) StringBufffer 类与这些缓冲区没有关系;
  • 2.2.2)最常用的是ByteBuffer 和 CharBuffer; (干货——最常用Buffer的是ByteBuffer 和 CharBuffer)
  • 2.2.3)每个缓冲区都具有: (干货——缓冲区的功能)

    • 2.2.3.1)一个容量: 它永远不能改变;
    • 2.2.3.2)一个读写位置: 下一个值将在此进行读写;
    • 2.2.3.3)一个界限: 超过它进行读写是没有意义的;
    • 2.2.3.4)一个可选标记:用于重复一个读入或写出操作;
    • 2.2.3.5)这些值满足下面的条件: 0 <= 标记<=读写位置 <=界限 <=容量; (干货——缓冲区中给定标记,读写位置,界限,容量的大小关系)
  • 2.2.4)使用缓冲区的主要目的是执行写, 然后读入循环。

    • 2.2.4.1)put方法:将值添加到缓冲区;
    • 2.2.4.2)flip方法:将界限设置到当前位置,并把位置复位到0;
    • 2.2.4.3)remaining方法: 现在在 remaining 方法返回整数时(它返回的值是 “界限—位置”),不断地调用get方法;
    • 2.2.4.4)clear方法: 在我们将缓冲区的所有值都读入后, 调用clear 使缓冲区为下一次写循环做好准备。 clear 方法将位置复位到0, 并将界限复位到容量;
    • 2.2.4.5)rewind 或 mark/reset方法: 如果你想重读缓冲区, 可以使用 rewind或 mark/reset 方法;
    • 2.2.4.6)ByteBuffer.allocate 或 ByteBuffer.wrap : 要获得缓冲区,调用它们;
    • 2.2.4.7)用来自某个通道的数据填充缓冲区, 或用缓冲区的数据写出到通道: (干货代码——用来自某个通道的数据填充缓冲区, 或用缓冲区的数据写出到通道)
ByteBuffer buffer = ByteBuffer.allocate(RECORD_SIZE);
channel.read(buffer);
channel.position(newpos);
buffer.flip();
channel.write(buffer);


【3】文件加锁机制(多个程序同时修改同一个文件的情形)

3.1)problem + solution

  • 3.1.1)problem: 多个程序同时修改同一个文件的情形, 这些程序需要以某种方式进行通信, 不然文件很容易损坏;
  • 3.1.2)solution: 文件锁可以解决这个问题, 它可以控制对文件或文件中的某个范围的字节 的访问; (干货——文件锁的功能)

3.2)看个荔枝:假设应用程序将用户个人信息存储在一个配置文件中, 当用户同时调用两个线程操作该文件时;

  • 3.2.1)第一个线程,应该锁定该文件, 而第二个线程发现这个文件被锁定了, 它必须决策是等待直至解锁还是跳过这个写操作过程;(干货——文件加锁机制后线程如何决策)
FileChannel channel = FileChannel.open(path);
FileLock lock = channle.lock();
或
FileLock lock = channel.tryLock();

Attention): 通道是对磁盘文件的一种抽象; (干货——再次提醒通道定义,即通道是对磁盘文件的一种抽象)

对上述代码的分析(Analysis):

  • A1)第一个调用会阻塞直至可获得锁, 而第二个调用将立即返回, 要么返回锁,要么在所不可获得的情况下返回null;
  • A2)这个文件将保持锁定状态,直至这个通道被关闭, 或者在锁上调用 release 方法;

3.3)你还可以通过下面的调用锁定文件的一部分:

FileLock lock(long start, long size, boolean shared)
或
FileLock tryLock(long start, long size, boolean shared)
  • 3.3.1)如果shared 标志为 false, 则锁定文件的目的是读写, 而如果为 true, 则这是一个共享锁, 它允许多个进程从文件中读入, 并组织任何进程获得独占锁; (干货——tryLock方法中shared数据域的含义)
  • 3.3.2)并非所有的os 都支持共享锁, 因此你可能会请求共享锁的时候得到的是独占的锁。调用 FileLock 类的 isShared 方法可以查询你所持有的锁的类型; (干货——共享锁和独占锁的定义)

Attention)如果你锁定了文件的尾部, 而这个文件的长度随后增长超过了锁定的部分, 那么增长出来的额外区域是未锁定的, 要想锁定所有的字节,可以用 Long.MAX_VALUE 来表示尺寸;

3.4)要确保在操作完成时释放锁,与往常一样, 最好在一个 try 语句中执行释放锁的操作:

try(FileLock lock = channle.lock())
{access th elocked file or segment
}

对以上代码的分析(Analysis):

  • A1)查看 tryLock API, 你会发现(以下内容转自 java SE 8 API): (干货中的干货——shared标识的排他锁或共享锁与StandardOpenOption的对应关系)
public abstract FileLock tryLock(long position,long size,boolean shared)throws IOException
Parameters:
position - The position at which the locked region is to start; must be non-negative
size - The size of the locked region; must be non-negative, and the sum position + size must be non-negative
shared - true to request a shared lock, false to request an exclusive lock
  • A2)shared 属性值(false=排他锁, 而true=共享锁)

    • NonReadableChannelException - If shared is true but this channel was not opened for reading
    • NonWritableChannelException - If shared is false but this channel was not opened for writing
  • 也就是说,
    • 共享锁(shared = true): 对应的是 FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)
    • 排他锁(shared = false): 对应的是FileChannel channel = FileChannel.open(path, StandardOpenOption.WRITE)
    • 以上对应关系出错的话,会抛出异常;

Attention) 文件加锁机制是依赖于os的, 下面是需要注意的:

  • A1)在某些系统中,文件加锁仅仅是建议性的, 如果一个应用未能获得锁,它仍旧可以向被另一个应用并发锁定的文件执行写操作;
  • A2)在某些系统中, 不能在锁定一个文件的同时将其映射到内存中;
  • A3)文件锁是由整个 java 虚拟机持有的。 如果有两个程序是由同一个虚拟机启动的, 那么他们不可能每一个都获得一个在同一个文件上的锁。当调用lock 或 tryLock 方法时, 如果虚拟机已经在同一个文件上持有另一个重叠的锁,那么这两个方法将抛出 OverlappingFileLockException;
  • A4)在一些系统中, 关闭一个通道会释放由 java 虚拟机持有的底层文件上的所有锁。 因此, 在同一个锁定文件上应该避免使用多个通道;(干货——在同一个锁定文件上应该避免使用多个通道)
  • A5)在网络文件系统上锁定文件时高度依赖于系统 的, 因此应该尽量避免;

java流与文件——内存映射文件相关推荐

  1. c语言 内存映射文件,内存映射文件

    内存映射文件 03/30/2017 本文内容 内存映射文件包含虚拟内存中文件的内容. 借助文件和内存空间之间的这种映射,应用(包括多个进程)可以直接对内存执行读取和写入操作,从而修改文件. 可以使用托 ...

  2. 快速读取内存文件-内存映射文件的方法

    1.前言     Windows提供了3种进行内存管理的方法: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个 ...

  3. 内存映射文件 写入 卡住_在Java中使用内存映射文件时检测(写入)失败

    内存映射文件 写入 卡住 内存映射文件是一个很好的并且经常被忽视的工具. 我不会在这里详细介绍它们的工作方式(使用 力 Google Luke!),但我将快速总结其优势: 操作系统提供的延迟加载和写入 ...

  4. 在Java中使用内存映射文件时检测(写入)失败

    内存映射文件是一个很好的并且经常被忽视的工具. 我不会在这里详细介绍它们的工作方式(使用 力 Google Luke!),但我将快速总结其优势: 操作系统提供的延迟加载和写入缓存(您不必自己编写,并且 ...

  5. 【java】java中内存映射文件和IO

    转载:https://leokongwq.github.io/2017/02/25/java-memorymapped-file-and-io.html 对大多数Java开发人员来说,Java中的内存 ...

  6. windows笔记-内存映射文件

    Windows提供了3种进行内存管理的方法: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据. ...

  7. Windows核心编程——》第十七章 内存映射文件 (Memory-Mapped Files)

    1.概览 (1)什么是内存映射文件 内存映射文件是由一个文件到一块内存的映射,使进程虚拟地址空间的某个区域与磁盘上某个文件的部分或全部内容的建立映射. 建立映射后,通过该区域可以直接对被映射的磁盘文件 ...

  8. Java基础:JavaNIO 之 内存映射文件原理

    1. 前言 最近研究Java中内存映射I/O.Java类库中的NIO中的内存映射文件MappedByteBuffer,相对于Java I/O是一个新的功能.特把适合用于处理大文件,在对大文件处理的时候 ...

  9. 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射...

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码. file ...

最新文章

  1. linux系统fuser命令,Linux系统使用Fuser命令的方法
  2. coreboot学习4:启动流程跟踪之romstage阶段
  3. efs解密-Advanced EFS Data Recovery2.1-含注册KEY
  4. 得到控制台窗口的句柄
  5. FISCO BCOS Solidity 智能合约Compiler error:Stack too deep, try removing local variables 如何传递超过16个参数变量
  6. 算法 第四版 2.1.25 不需要交换的插入排序
  7. cfd软件matlab,【流体】| 10个目前流行的CFD仿真软件,你了解几个?
  8. qzezoj 1641 黑暗城堡
  9. html设计一个网页表格,21个新奇古怪的网页表格设计
  10. [windows]win10家庭版切换到管理员账户
  11. 华为AR路由器端口配置trunk_锐捷交换机和路由器的一些基础命令
  12. Linux系统中的管道通信
  13. 计算机专业如何晋级正高级,已有软考高级证书如何获得正高级职称?
  14. 组件,控件,用户控件
  15. 计算机网络信息安全特征,计算机基础知识:网络信息安全的概述及特征
  16. wine linux 64位下载,Wine 1.9 开发者版本可以下载了
  17. java图书借阅管理系统304
  18. LM321 低功耗单运算放大器 1MHZ增益带宽积 用于充电器 适配器
  19. 6种原型设计工具大比对! Axure,Invision, 墨刀……哪款适合你?
  20. php获取另一个网页内容,php获取网页内容的三种方法

热门文章

  1. P4288 [SHOI2014]信号增幅仪 最小圆覆盖
  2. cf1009F. Dominant Indices
  3. P1247 取火柴游戏
  4. 关于__int128高精度运算
  5. CodeForces 901D Weighting a Tree(结论)
  6. 【无码专区12】子集和(背包dp)
  7. P4301-[CQOI2013]新Nim游戏【线性基】
  8. 欢乐纪中A组莫名其妙赛【2019.6.6】
  9. 2018/7/6-纪中某C组题【jzoj1192,jzoj1397,jzoj1736】
  10. 2021“MINIEYE杯”中国大学生算法设计超级联赛(5)Random Walk 2(推式子+矩阵逆+矩阵乘)