最近在写一个txt文本小说阅读器,在解析几M以上的txt文件时,总是由于内存溢出报错,要不然就是运行太慢,在网上找了集中方法后,最后觉得MappedByteBuffer最合适,不仅解决了以上的问题,还方便了阅读时的分章。
.getChannel().map(FileChannel.MapMode.READ_ONLY,
0, 1000);
final int BUFFER_SIZE = 0x300000;// 缓冲区大小为3M
byte[] dst = new byte[BUFFER_SIZE];// 每次读出3M的内容
long start = System.currentTimeMillis(); //获取解析开始的时间
for (int offset = 0; offset < inputBuffer.capacity(); offset += BUFFER_SIZE) {
if (inputBuffer.capacity() - offset >= BUFFER_SIZE) {
for (int i = 0; i < BUFFER_SIZE; i++)
dst[i] = inputBuffer.get(offset + i);
} else {
for (int i = 0; i < inputBuffer.capacity() - offset; i++)
dst[i] = inputBuffer.get(offset + i);
}
int length = (inputBuffer.capacity() % BUFFER_SIZE == 0) ? BUFFER_SIZE
//获取当次读取的长度
: inputBuffer.capacity() % BUFFER_SIZE;
--
---------------
MappedByteBuffer在java帮助文档的解析-------------------
-
public abstract class MappedByteBuffer
extends
ByteBuffer
直接字节缓冲区,其内容是文件的内存映射区域。
映射的字节缓冲区是通过 FileChannel.map
ByteBuffer
映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。
映射的字节缓冲区的内容可以随时更改,例如,在此程序或另一个程序更改了对应的映射文件区域的内容的情况下。这些更改是否发生(以及何时发生)与操作系统无关,因此是未指定的。
除此之外,映射的字节缓冲区的功能与普通的直接字节缓冲区完全相同。
-------------------------------------------------------------------------------------
MappedByteBuffer inputBuffer = new RandomAccessFile(f, "r")
--------------------------------------------------------------------------------
* map(FileChannel.MapMode mode,long position, long size)
* mode - 根据是按只读、读取/写入或专用(写入时拷贝)来映射文件,分别为 FileChannel.MapMode 类中所定义的READ_ONLY、READ_WRITE 或 PRIVATE 之一
* position - 文件中的位置,映射区域从此位置开始;必须为非负数
* size - 要映射的区域大小;必须为非负数且不大于 Integer.MAX_VALUE
--------------
解析过程代码-------------------------------
MappedByteBuffer在解析大文本数据时速度很快,但也存在一些问题,主要就是内存占用和文件关闭等不确定问题。被MappedByteBuffer打开的文件只有在垃圾收集时才会被关闭,而这个点是不确定的。
这里提供一种解决方案(来自网络):
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;
}
});