java处理大文本方案
转载自: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. 随时随地写入
下面来看代码:

1 package study;
2 import java.io.FileInputStream;
3 import java.io.FileOutputStream;
4 import java.nio.ByteBuffer;
5 import java.nio.MappedByteBuffer;
6 import java.nio.channels.FileChannel;
7
8 public class MapMemeryBuffer {
9
10 public static void main(String[] args) throws Exception {
11 ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024);
12 byte[] bbb = new byte[14 * 1024 * 1024];
13 FileInputStream fis = new FileInputStream("e://data/other/UltraEdit_17.00.0.1035_SC.exe");
14 FileOutputStream fos = new FileOutputStream("e://data/other/outFile.txt");
15 FileChannel fc = fis.getChannel();
16 long timeStar = System.currentTimeMillis();// 得到当前的时间
17 fc.read(byteBuf);// 1 读取
18 //MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
19 System.out.println(fc.size()/1024);
20 long timeEnd = System.currentTimeMillis();// 得到当前的时间
21 System.out.println("Read time :" + (timeEnd - timeStar) + "ms");
22 timeStar = System.currentTimeMillis();
23 fos.write(bbb);//2.写入
24 //mbb.flip();
25 timeEnd = System.currentTimeMillis();
26 System.out.println("Write time :" + (timeEnd - timeStar) + "ms");
27 fos.flush();
28 fc.close();
29 fis.close();
30 }
31
32 }
33 运行结果:
34 14235
35 Read time :24ms
36 Write time :21ms
37 我们把标注1和2语句注释掉,换成它们下面的被注释的那条语句,再来看运行效果。14235
38 Read time :2ms
39 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.
这里提供一种解决方案:

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(byteBuffer, new Object[0]);
cleaner.clean();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});

关于MappedByteBuffer资源释放问题
FileChannel.map 方法创建的。映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。此类用特定于内存映射文件区域的操作扩展 ByteBuffer 类。 这个类本身的设计是不错的,比直接操作byte[]方便多了。[])。但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即
MappedByteBuffer,文件映射。
的内容,并导致在访问时或访问后的某个时刻抛出未指定的异常。因此强烈推荐采取适当的预防措施,以避免此程序或另一个同时运行的程序对映射的文件执行操作
(读写文件内容除外)。

1 //文件复制
2 public void copyFile(String filename,String srcpath,String destpath)throws IOException {
3 File source = new File(srcpath+"/"+filename);
4 File dest = new File(destpath+"/"+filename);
5 FileChannel in = null, out = null;
6 try {
7 in = new FileInputStream(source).getChannel();
8 out = new FileOutputStream(dest).getChannel();
9 long size = in.size();
10 MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size);
11 out.write(buf);
12 in.close();
13 out.close();
14 source.delete();//文件复制完成后,删除源文件
15 }catch(Exception e){
16 e.printStackTrace();
17 } finally {
18 in.close();
19 out.close();
20 }
21 }


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

不知道为什么SUN不提供ByteBuffer的派生。毕竟这是一个很实用的类,如果允许派生,那么我就可以操作的就不仅仅限于堆内存和文件了,我可以扩展到任何存储设备。
java处理大文本方案的更多相关文章
- Java查询大文本
但JAVA本身缺少相应的类库,需要硬编码才能实现结构化文件计算,代码复杂且可读性差,难以实现高效的并行处理. 使用免费的集算器可以弥补这一不足.集算器封装了丰富的结构化文件读写和游标计算函数,书写简单 ...
- 【Java】大文本字符串滤重的简单方案~
本文章也同步至本人的CSDN博客中: http://blog.csdn.net/u012881584/article/details/70477832 今天来说一个Java中处理大文本字符串虑重的两个 ...
- java处理大文本2G以上
面试中经常碰到类似问题,问题的关键我觉得是用设置一个缓冲区 还有一个思路 是通过Linux split 命令将文件直接切割成小文件,再进行处理再汇总. 或者jdk7提供的 forkjoin 框架,利用 ...
- Java调用SqlLoader将大文本导入数据库
Java调用SqlLoader将大文本导入数据库 业务场景:将一千万条数据,大约500M的文本文档的数据导入到数据库 分析:通过Java的IO流解析txt文本文档,拼接动态sql实现insert入库, ...
- ElasticStack系列之十七 & 大文本搜索性能提升方案
1. 什么是大文本?具体是什么? 首先需要理解,ElasticSearch 建立索引完成全文检索的前提是将待检索的信息导入到 ElasticSearch 中.而有的信息对应的正文内容会非常的打,可能达 ...
- Android OCR文字识别 实时扫描手机号(极速扫描单行文本方案)
身份证识别:https://github.com/wenchaosong/OCR_identify 遇到一个需求,要用手机扫描纸质面单,获取面单上的手机号,最后决定用tesseract这个开源OCR库 ...
- java filechannel大文件的读写
java读取大文件 超大文件的几种方法 转自:http://wgslucky.blog.163.com/blog/static/97562532201332324639689/ java 读取一个 ...
- Android自定义ScrollView分段加载大文本数据到TextView
以下内容为原创,转载时请注明链接地址:http://www.cnblogs.com/tiantianbyconan/p/3311658.html 这是我现在碰到的一个问题,如果需要在TextView中 ...
- jdbc基础 (三) 大文本、二进制数据处理
LOB (Large Objects) 分为:CLOB和BLOB,即大文本和大二进制数据 CLOB:用于存储大文本 BLOB:用于存储二进制数据,例如图像.声音.二进制文件 在mysql中,只有B ...
随机推荐
- 升级 mysql5.6 配置文件my.cnf sql_mode 解析与设置问题
sql_mode是个很容易被忽视的变量,默认值是空值,在这种设置下是可以允许一些非法操作的,比如允许一些非法数据的插入.在生产环境必须将这个值设置为严格模式,所以开发.测试环境的数据库也必须要设置,这 ...
- Comparable接口和Comparator接口
1.一个类在设计之初就要实现对该类对象的排序功能,那么这个类要实现Comparable接口,实现public int compareTo(T t)方法.如代码中的Student类.对于实现Compar ...
- Mybatis学习笔记二
本篇内容,紧接上一篇内容Mybatis学习笔记一 输入映射和输出映射 传递简单类型和pojo类型上篇已介绍过,下面介绍一下包装类型. 传递pojo包装对象 开发中通过可以使用pojo传递查询条件.查询 ...
- (译文)开始学习Vue——构建你的第一个Vue应用
我们要构建如下组件:(最终代码在这里:https://codesandbox.io/s/38k1y8x375) 开始 Vue是支持单文件组件的,但是我们不准备这么做.你也可以构建一个全局的组件,通过V ...
- New UWP Community Toolkit - RadialProgressBar
概述 UWP Community Toolkit 中有一个圆形的进度条控件 - RadialProgressBar,本篇我们结合代码详细讲解 RadialProgressBar 的实现. Radi ...
- C语言博客作业—指针
一.PTA实验作业 题目1: 求出数组中最大数和次最大数 1. 本题PTA提交列表 2. 设计思路 定义max表示范围数组中的最大数(初值设为a[0]),z表示找到的元素在数组中的位置: 定义指针*b ...
- Django SNS 微博项目开发
1.功能需求 一个人可以follow很多人 一个用户如果发了新weibo会自动推送所有关注他的人 可以搜索.关注其它用户 可以分类关注 用户可以发weibo, 转发.收藏.@其它人 发微博时可选择公开 ...
- 多线程socket UDP收发数据
多线程socket收发数据 from threading import Thread from socket import * def sendData(): while True: sendInfo ...
- iOS开发之Objective-C与JavaScript的交互
UIWebView是iOS最常用的SDK之一,它有一个stringByEvaluatingJavaScriptFromString方法可以将javascript嵌入页面中,通过这个方法我们可以在iOS ...
- 关于webService发布的wsdl中的import问题解决
大家都知道jdk1.6及以后都支持了对webService的原生态的支持:它在发布时会生成一个wsdl和一个xsd(一个类只生成一个xsd)所以就保留了引用关系,如下: <?xml versio ...