当前位置: 首页 > 编程日记 > 正文

java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射

http://langgufu.iteye.com/blog/2107023


java处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的Io类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer。

MappedByteBuffer是java nio引入的文件内存映射方案,读写性能极高。NIO最主要的就是实现了对异步操作的支持。其中一种通过把一个套接字通道(SocketChannel)注册到一个选择器(Selector)中,不时调用后者的选择(select)方法就能返回满足的选择键(SelectionKey),键中包含了SOCKET事件信息。这就是select模型。
       SocketChannel的读写是通过一个类叫ByteBuffer(java.nio.ByteBuffer)来操作的.这个类本身的设计是不错的,比直接操作byte[]方便多了. ByteBuffer有两种模式:直接/间接.间接模式最典型(也只有这么一种)的就是HeapByteBuffer,即操作堆内存 (byte[]).但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射.
     先中断一下,谈谈操作系统的内存管理.一般操作系统的内存分两部分:物理内存;虚拟内存.虚拟内存一般使用的是页面映像文件,即硬盘中的某个(某些)特殊的文件.操作系统负责页面文件内容的读写,这个过程叫"页面中断/切换". MappedByteBuffer也是类似的,你可以把整个文件(不管文件有多大)看成是一个ByteBuffer.MappedByteBuffer 只是一种特殊的 ByteBuffer ,即是ByteBuffer的子类。 MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。

三种方式:
              FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                    
a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)
b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)
c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE)

三个方法:

a. fore();缓冲区是READ_WRITE模式下,此方法对缓冲区内容的修改强行写入文件
b. load()将缓冲区的内容载入内存,并返回该缓冲区的引用
c. isLoaded()如果缓冲区的内容在物理内存中,则返回真,否则返回假

三个特性:

    调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:

a. 读取快
b. 写入快
c. 随时随地写入

下面来看代码:

[java] view plaincopy

  1.         ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024);  
  2.         byte[] bbb = new byte[14 * 1024 * 1024];  
  3.         FileInputStream fis = new FileInputStream("e://data/other/UltraEdit_17.00.0.1035_SC.exe");  
  4.         FileOutputStream fos = new FileOutputStream("e://data/other/outFile.txt");  
  5.         FileChannel fc = fis.getChannel();  
  6.         long timeStar = System.currentTimeMillis();// 得到当前的时间  
  7.         fc.read(byteBuf);// 1 读取  
  8.         //MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());  
  9.         System.out.println(fc.size()/1024);  
  10.         long timeEnd = System.currentTimeMillis();// 得到当前的时间  
  11.         System.out.println("Read time :" + (timeEnd - timeStar) + "ms");  
  12.         timeStar = System.currentTimeMillis();  
  13.         fos.write(bbb);//2.写入  
  14.         //mbb.flip();  
  15.         timeEnd = System.currentTimeMillis();  
  16.         System.out.println("Write time :" + (timeEnd - timeStar) + "ms");  
  17.         fos.flush();  
  18.         fc.close();  
  19.         fis.close();  


  20. 运行结果:  
  21. 14235  
  22. Read time :24ms  
  23. Write time :21ms  
  24. 我们把标注12语句注释掉,换成它们下面的被注释的那条语句,再来看运行效果。14235  
  25. Read time :2ms  
  26. Write time :0ms  


可以看出速度有了很大的提升。MappedByteBuffer的确快,但也存在一些问题,主要就是内存占用和文件关闭等不确定问题。被MappedByteBuffer打开的文件只有在垃圾收集时才会被关闭,而这个点是不确定的。在javadoc里是这么说的:A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself  is garbage-collected.


这里提供一种解决方案:

[java] view plaincopy
  1. AccessController.doPrivileged(new PrivilegedAction() {  
  2.   public Object run() {  
  3.     try {  
  4.       Method getCleanerMethod = buffer.getClass().getMethod("cleaner"new Class[0]);  
  5.       getCleanerMethod.setAccessible(true);  
  6.       sun.misc.Cleaner cleaner = (sun.misc.Cleaner)   
  7.       getCleanerMethod.invoke(byteBuffer, new Object[0]);  
  8.       cleaner.clean();  
  9.     } catch (Exception e) {  
  10.       e.printStackTrace();  
  11.     }  
  12.     return null;  
  13.   }  
  14. });  

关于MappedByteBuffer资源释放问题

JDK1.4中加入了一个新的包:NIO(java.nio.*)。这个库最大的功能(我认为)就是增加了对异步套接字的支持。其实在 其他语言中,包括在最原始的SOCKET实现(BSD SOCKET),这是一个早有的功能:异步回调读/写事件,通过选择器动态选择感兴趣的事件,等等。
先谈谈操作系统的内存管理。一般操作系统的内存分两部分:物理内存;虚拟内存。虚拟内存一般使用的是页面映像文件,即硬盘中的某个(某些)特殊的文件.操作系统负责页面文件内容的读写,这个过程叫"页面中断/切换"。
MappedByteBuffer也是类似的,你可以把整个文件(不管文件有多大)看成是一个ByteBuffer。这是一个很好的设计,除了令人头疼的一点在后面会讲到。

java.lang.Object
   java.nio.Buffer
      java.nio.ByteBuffer
          java.nio.MappedByteBuffer

MappedByteBuffer是一个比较方便使用的类。其内容是文件的内存映射区域。映射的字节缓冲区是通过FileChannel.map 方法创建的。映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。此类用特定于内存映射文件区域的操作扩展 ByteBuffer 类。 这个类本身的设计是不错的,比直接操作byte[]方便多了。
ByteBuffer有两种模式:直接/间接。间接模式最典型(也只有这么一种)的就是HeapByteBuffer,即操作堆内存(byte [])。但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射。
在JDK API文档中这样描述的:
全部或部分映射的字节缓冲区可能随时成为不可访问的,例如,如果我们截取映射的文件。试图访问映射的字节缓冲区的不可访问区域将不会更改缓冲区 的内容,并导致在访问时或访问后的某个时刻抛出未指定的异常。因此强烈推荐采取适当的预防措施,以避免此程序或另一个同时运行的程序对映射的文件执行操作 (读写文件内容除外)。
MappedByteBuffer只能通过调用FileChannel的map()取得,再没有其他方式.但是令人奇怪的是,SUN提供了map()却没有提供unmap().这样会导致什么后果呢?
这样,问题就出现了。通过MappedByteBuffer实现文件复制功能非常容易,可以用以下方法来实现。
   //文件复制public void copyFile(String filename,String srcpath,String destpath)throws IOException {File source = new File(srcpath+"/"+filename);File dest = new File(destpath+"/"+filename);FileChannel in = null, out = null;try { in = new FileInputStream(source).getChannel();out = new FileOutputStream(dest).getChannel();long size = in.size();MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);out.write(buf);in.close();out.close();source.delete();//文件复制完成后,删除源文件}catch(Exception e){e.printStackTrace();} finally {in.close();out.close();}}



但是如果要实现文件文件复制完成后,删除源文件,以上方法就有问题。因为在source.delete()时,会返回false,删除失败,主 要原因是变量buf仍然有源文件的句柄,文件处于不可删除状态。既然MappedByteBuffer是从FileChannel中map()出来的,为 什么它又不提供unmap()呢?SUN自己也没有讲清楚为什么。O'Reilly的<<Java NIO>>中说是因为"安全"的原因,但是到底unmap()会怎么不安全,作者也没有讲清楚。
在sun网站也有相应的BUG报告:bug id:4724038链接为http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038,但是sun自己不认为是BUG,而只是一个RFE(Request For Enhancement),有待改进。
好在有个叫bellomi的网友提出了一个解决方法,我也测试过,可以实现期望的功能。具体实现代码如下:
   public static void clean(final Object buffer) throws Exception {AccessController.doPrivileged(new PrivilegedAction() {public Object run() {try {Method getCleanerMethod = buffer.getClass().getMethod("cleaner",new Class[0]);getCleanerMethod.setAccessible(true);sun.misc.Cleaner cleaner =(sun.misc.Cleaner)getCleanerMethod.invoke(buffer,new Object[0]);cleaner.clean();} catch(Exception e) {e.printStackTrace();}return null;}});
}


不知道为什么SUN不提供ByteBuffer的派生。毕竟这是一个很实用的类,如果允许派生,那么我就可以操作的就不仅仅限于堆内存和文件了,我可以扩展到任何存储设备。

转载于:https://www.cnblogs.com/leeeee/p/7276076.html

相关文章:

HTML5 Canvas编写五彩连珠(3):设计

在看了几篇Canvas相关的文章后&#xff0c;发现前两节的代码实现还是有问题&#xff0c;因为知道的少&#xff0c;所以只能在自己已知的知识上做实现。不过还好&#xff0c;这是一个发现的过程&#xff0c;也是一个纠错和完善的过程。我第一次尝试一边学习一遍写博客&#xff0…

SQL面试宝典一:

1.什么是sql Injection&#xff08;sql 注入&#xff09;&#xff1f;如何防止&#xff1f; 答&#xff1a;是一种恶意将sql代码添加到输入参数中&#xff0c;传递到sql服务器解析并执行的一种攻击手法。 防止&#xff1a;1.对用户的输入进行校验&#xff0c;可以通过正则表达…

java注解的执行顺序_深入理解Spring的@Order注解和Ordered接口

前言Spring的Order注解或者Ordered接口大家都知道是控制顺序的&#xff0c;那么它们到底是控制什么顺序的&#xff1f;是控制Bean的注入顺序&#xff0c;还是Bean的实例化顺序&#xff0c;还是Bean的执行顺序呢&#xff1f;那么我们先直接给出结论再来验证结论。结论&#xff1…

数据驱动安全需三大核心新技术

要做到数据驱动安全&#xff0c;齐向东认为需要三大核心技术。第一个核心技术是大数据采集器&#xff0c;第二个是大数据引擎&#xff0c;第三个是机器学习挖掘、重要安全问题定位准确。转载于:https://www.cnblogs.com/1992825-Amelia/p/4854220.html

[转]BI 问答

http://blog.bridata.ca/?cat16 前几天Post 了一些BI 的面试问题&#xff0c;感兴趣的人很多&#xff0c;有很多人问我答案以此来评估一下自己的知识水平。坦白地说我没有写在纸上的具体答案&#xff0c;事实上每个问题也没有具体和精确的答案&#xff0c;所谓面试就不是笔试&…

没有学不会的C++:用户自定义的隐式类型转换

C 中的类型转换包含内建类型的转换和用户自定义类型的转换&#xff0c;而这两者都又可分为隐式转换和显示转换&#xff0c;所以一共有如下四象限表格中的 A、B、C、D 四种情况 隐式转换显示转换(casting)内建类型转换 (int, float ...)AB用户自定义类型转换(类 vs 类; 类 vs 内…

python scrapy菜鸟教程_scrapy学习笔记(一)快速入门

安装ScrapyScrapy是一个高级的Python爬虫框架&#xff0c;它不仅包含了爬虫的特性&#xff0c;还可以方便的将爬虫数据保存到csv、json等文件中。首先我们安装Scrapy。pip install scrapy在Windows上安装时可能会出现错误&#xff0c;提示找不到Microsoft Visual C。这时候我们…

执行eclipse,迅速failed to create the java virtual machine。

它们必须在一排&#xff0c;否则会出现The Eclipse executable launcher was unable to locate its companion shared library的错误 打开eclipse文件夹下的eclipse.ini文件。改动–launcher.XXMaxPermSize属性&#xff0c;当中此属性有两处 -startup plugins/org.eclipse.equi…

vue打包后图片找不到情况

打包之前需要修改如下配置文件&#xff1a; 配置文件一&#xff1a;build>>>utils.js (修改publicPath:"../../" , 这样写是处理打包后找不到静态文件&#xff08;图片路径失效&#xff09;的问题) 配置文件二&#xff1a;config>>>index.js(修改a…

UBUNTU安装SSH和xrdp

一、安装SSH&#xff0c;通过PUTTY访问 命令&#xff1a;sudo apt-get install ssh 查看&#xff1a;netstat -l 二、安装xrdp&#xff0c;通过远程桌面访问 命令&#xff1a;sudo apt-get install xrdp 开启远程桌面访问权限 系统-->首选项-->remote desktop 三、去掉远…

python中opencv中inrange用法_python-opencv中的cv2.inRange函数

本次目标是将一副图像从rgb颜色空间转换到hsv颜色空间&#xff0c;颜色去除白色背景部分具体就调用了cv2的两个函数&#xff0c;一个是rgb转hsv的函数具体用法hsv cv2.cvtColor(rgb_image, cv2.COLOR_BGR2HSV)然后利用cv2.inRange函数设阈值&#xff0c;去除背景部分mask cv2…

[转]C++11 随机数学习

相对于C 11之前的随机数生成器来说&#xff0c;C11的随机数生成器是复杂了很多。这是因为相对于之前的只需srand、rand这两函数即可获取随机数来说&#xff0c;C11提供了太多的选择和东西。 随机数生成算法&#xff1a; 随机数生成算法有很多&#xff0c;C11之前的C/C只…

Linux Shell ssh登录脚本

Linux 登陆服务器敲命令太多,某时候确实不便,所以就用shell写了一个 我的blog地址: http://www.cnblogs.com/caoguo 一.说明 支持秘密和密钥两种格式用户名和密码都是写文件的,明文保存二.配置 密码文件配置:序号:IP:端口:用户:密码:说明 1:192.168.88.128:22:root:toor:虚拟机…

C# 温故而知新:Stream篇(二)

C# 温故而知新&#xff1a;Stream篇&#xff08;二&#xff09; TextReader 和StreamReader 目录&#xff1a; 为什么要介绍 TextReader&#xff1f; TextReader的常用属性和方法 TextReader 示例 从StreamReader想到多态 简单介绍下Encoding 编码 StreamReader 的定义及作用 S…

usaco Pollutant Control

第一问是求最小割。第二问求最小割中集合中边最少的集合的大小。 第三问求集合中边最少且字典序最小的边的下标。 第一问直接求最大流就能解&#xff0c;第二问将原来的边的容量都改为1&#xff0c;求出来的最大流就是元素最少的一个最小割的大小。 将容量都改为1之后&#xff…

洛谷P4705 玩游戏(生成函数+多项式运算)

题面 传送门 题解 妈呀这辣鸡题目调了我整整三天……最后发现竟然是因为分治\(NTT\)之后的多项式长度不是\(2\)的幂导致把多项式的值存下来的时候发生了一些玄学错误……玄学到了我\(WA\)的点全都是\(WA\)在\(2\)的幂次行里…… 看到这种题目二话不说先推倒 \[ \begin{aligned}…

blast程序 介绍 简介

每次找都挺麻烦&#xff0c;又记不住&#xff0c;于是抄下来&#xff1a; blastp:将待查询的蛋白质序列及其互补序列一起对蛋白质序列数据库进行查询&#xff1b;blastn:将待查询的核酸序列及其互补序列一起对核酸序列数据库进行查询&#xff1b;blastx:先将待查询的核酸序列按…

java泛型的实现和原理_java 泛型实现原理

泛型思想最早在C语言的模板(Templates)中产生&#xff0c;Java后来也借用了这种思想。虽然思想一致&#xff0c;但是他们存在着本质性的不同。C中的模板是真正意义上的泛型&#xff0c;在编译时就将不同模板类型参数编译成对应不同的目标代码&#xff0c;List和List是两种不同的…

java out of range_关于Parameter index out of range求解决办法

程序&#xff1a;提示参数越界&#xff0c;但我实在不知道我到底哪里越界了。明明该我那样写的嘛。求高手帮我看看&#xff0c;现在我是弄得我有气无力了&#xff01;要死了。在去死亡的路上等着你帮帮我&#xff01;Document : replyokCreated on : 2008-9-29, 6:05:31Autho…

FineReport——权限分配以及自定义首页

权限分配可以有两种方法&#xff0c;第一种方法是根据部门职位分配权限&#xff0c;第二种是根据角色分配权限&#xff1b; FR自带有三个JQ对象&#xff0c;用以保存用户名参数/角色参数/部门参数——$fr_username/$fr_authority/$fr_userposition 根据部门职位&#xff1a; 以…

去掉[]中的英文(正则表达式)C#

这个问题本来是以为信息科技大学的老师问蒋委员长的问题,蒋委员长用正则表达式完成了这个问题 1,问题的情况有哪些? abc[abc]abc,abc[-abc]abc,abc[一abc]abc,abc[一abc一]abc等等. 2,问题的解决目标? 写一个通用的方法来完成提出的问题. 3,解决方案 -->正则表达式方法 其…

Event Loop

事件队列 Javascript是单线程&#xff0c;单线程就意味着所有任务需要排队。然后会将所有任务分成两类&#xff1a;同步任务和异步任务&#xff01;同步任务&#xff1a;在主线程上执行的任务&#xff0c;只有前一个任务执行完成&#xff0c;才会执行后一个&#xff01;异步任务…

java makefile jar包_java makefile学习实践(编译的javac命令写在makefile中,运行命令java写在shell脚本中)...

学习makefile教程&#xff0c;ubuntu中文网1.写一个简单的java项目&#xff0c;不需要外部jar,用的简单的importjava.util.ArrayList;是可以从CLASSPATH环境变量中找到的&#xff0c;在javac阶段不需要特殊添加-cphellocatHellocat.javaimportjava.util.ArrayList;importjava.u…

Python字符编码详解

Python字符编码详解 转自http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html Python字符编码详解 本文简单介绍了各种常用的字符编码的特点&#xff0c;并介绍了在python2.x中如何与编码问题作战 &#xff1a;&#xff09; 请注意本文关于Python的内容仅适用于2.x&a…

《编写有效用例》读书笔记1

第一章 引言 本章主要介绍用例是什么样子的&#xff0c;并描述为什么不同的项目组需要采用不同 的用例编写风格以及在什么地方使用用例有利于做需求收集工作&#xff0c;也让我们了解 在编写用例之前&#xff0c;需要做哪些准备工作。 用例是代表系统中各个项目相关人员之间就系…

顺序结构,判断结构 if,switch

1&#xff1a;顺序结构&#xff1a;从上往下执行程序代码&#xff0c;为顺序结构 ---------------------------------------------------------------------- 2&#xff1a;判断结构&#xff1a; if 如果 判断是两个选择一个&#xff0c;要么对要么错 if中的条件表达式 返回…

php转换文字Unicode,php实现将中文转为unicode的方法

相关函数说明&#xff1a;iconv命令是用来转换文件的编码方式的&#xff0c;比如它可以将UTF8编码的转换成GB18030的编码&#xff0c;反过来也行。str_split() 函数把字符串分割到数组中。bin2hex() 函数把 ASCII 字符的字符串转换为十六进制值。字符串可通过使用 pack() 函数再…

kail安装和vmtools安装

因位太费劲我直接把我做的Word文档直接上传了&#xff0c;如果想安装可以下载&#xff0c;我就不麻烦在写一遍了&#xff0c;这个教程主要给小白讲的&#xff0c;大佬请绕过 kail安装教程.docx https://pan.wps.cn/l/sm43o7f 密码&#xff1a;f43341转载于:https://www.cnblogs…

Windows计数器做性能监控(window server 2008服务器)

使用Windows计数器 一、创建数据收集器集 二、创建数据收集器 三、使用数据收集器 1、修改数据收集器的属性 2、手动启用、手动停止数据收集器集 3、计划任务 4、在性能监视器中查看 一、性能监视器 Windows 服务器操作系统提供一个名为“性能监视器”的图形工具&#xff0c;可…

使用浏览器wpf应用程序时访问数据库需要报权限错误的解决方法

在这篇wpf教程中&#xff0c;如果选用浏览器wpf应用程序模板我遇到了 访问数据库时权限不够 不能打开连接 将项目属性的安全性中设置为完全信任后即解决 转载于:https://www.cnblogs.com/langu/archive/2012/03/29/2423620.html