说到高速缓存存储,处理读写文件,那就不得不说MappedByteBuffer。

看了好多文章以后写一下自己的总结。

在这里先介绍一下相关的类与方法。

先说一下Buffer、ByteBuffer、MappedByteBuffer这几个类之间的关系。

public abstract class Buffer {

    // Invariants: mark <= position <= limit <= capacity
private int mark = -;
private int position = ;
private int limit;
private int capacity;
long address;
......
} public abstract class ByteBuffer extends Buffer implements Comparable { // These fields are declared here rather than in Heap-X-Buffer in order to
// reduce the number of virtual method invocations needed to access these
// values, which is especially costly when coding small buffers.
//
final byte[] hb; // Non-null only for heap buffers
final int offset;
boolean isReadOnly; // Valid only for heap buffers
boolean bigEndian;
boolean nativeByteOrder;
......
}
//字节数组final byte[] hb就是所指的那块内存缓冲区 public abstract class MappedByteBuffer extends ByteBuffer{
private final FileDescriptor fd;
......
}

public abstract class MappedByteBuffer extends ByteBuffer 直接字节缓冲区,其内容是文件的内存映射区域。

映射的字节缓冲区是通过 FileChannel.map 方法创建的。此类用特定于内存映射文件区域的操作扩展 ByteBuffer 类。 
映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。 
映射的字节缓冲区的内容可以随时更改,例如,在此程序或另一个程序更改了对应的映射文件区域的内容的情况下。这些更改是否发生(以及何时发生)与操作系统无关,因此是未指定的。 
全部或部分映射的字节缓冲区可能随时成为不可访问的,例如,如果我们截取映射的文件。试图访问映射的字节缓冲区的不可访问区域将不会更改缓冲区的内容,并导致在访问时或访问后的某个时刻抛出未指定的异常。因此强烈推荐采取适当的预防措施,以避免此程序或另一个同时运行的程序对映射的文件执行操作(读写文件内容除外)。

除此之外,映射的字节缓冲区的功能与普通的直接字节缓冲区完全相同。

public RandomAccessFile(File file, String mode)throws FileNotFoundException
创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。将创建一个新的 FileDescriptor 对象来表示此文件的连接。 
r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 
"rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。

public final FileChannel getChannel()返回与此文件关联的唯一 FileChannel 对象。 
返回通道的 java.nio.channels.FileChannel#position()position 将始终等于 getFilePointer 方法返回的此对象的文件指针偏移量。显式或者通过读取或写入字节来更改此对象的文件指针偏移量将更改通道的位置,反之亦然。通过此对象更改此文件的长度将更改通过文件通道看到的长度,反之亦然。

public abstract MappedByteBuffer map(FileChannel.MapMode mode,long position,long size)throws IOException将此通道的文件区域直接映射到内存中。 
mode - 根据是按只读、读取/写入或专用(写入时拷贝)来映射文件,分别为 FileChannel.MapMode类中所定义的 READ_ONLY、READ_WRITE 或 PRIVATE 之一
position - 文件中的位置,映射区域从此位置开始;必须为非负数
size - 要映射的区域大小;必须为非负数且不大于 Integer.MAX_VALUE

下面一个运行的例子:

package com.tzx.ne;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel; public class MappedByteBufferDemo {
public static void main(String[] args) throws Exception{
/**
* output: 0.001s(读)
* input: 0.11s(写)
* */
MappedByteBufferTest();
/**
* size=1024*8
* out: 0.0s
* input: 0.014s
* */
/**
* size=1024*1024*8
* output: 0.01s
* input: 0.014s
* */
/**
* size=80
* output: 0.0s
* input: 0.546s
* */
//BufferTest();
/**
* time: 0.585s
* */
//BufferedInputStreamTest();
} /*
* 测试结果与Buffer size有关
*/
// 1、使用MappedByteBuffer: 0.7s
public static void MappedByteBufferTest() throws Exception{
String srcFile = "F:\\Ebook\\偷天.txt";
String destFile = "F:\\Ebook\\toutian.txt";
RandomAccessFile rafi = new RandomAccessFile(srcFile, "r");
RandomAccessFile rafo = new RandomAccessFile(destFile, "rw");
FileChannel fci = rafi.getChannel();
FileChannel fco = rafo.getChannel();
long size = fci.size();
byte b;
long start = System.currentTimeMillis();
MappedByteBuffer mbbi = fci.map(FileChannel.MapMode.READ_ONLY, , size);
System.out.println("output: " + (double) (System.currentTimeMillis() - start) / + "s");
MappedByteBuffer mbbo = fco.map(FileChannel.MapMode.READ_WRITE, , size);
start = System.currentTimeMillis();
for (int i = ; i < size; i++) {
b = mbbi.get(i);
mbbo.put(i, b);
}
fci.close();
fco.close();
rafi.close();
rafo.close();
System.out.println("input: " + (double) (System.currentTimeMillis() - start) / + "s");
} // 2、自己处理Buffer(RandomAccessFile): 0.13s
public static void BufferTest() throws Exception{
String srcFile = "F:\\Ebook\\偷天.txt";
String destFile = "F:\\Ebook\\toutian.txt";
RandomAccessFile rafi = new RandomAccessFile(srcFile, "r");
RandomAccessFile rafo = new RandomAccessFile(destFile, "rw"); byte[] buf = new byte[];
long start = System.currentTimeMillis();
int c = rafi.read(buf);
System.out.println("output: " + (double) (System.currentTimeMillis() - start) / + "s");
start = System.currentTimeMillis();
while (c > ) {
if (c == buf.length) {
rafo.write(buf);
} else {
rafo.write(buf, , c);
} c = rafi.read(buf);
}
System.out.println("input: " + (double) (System.currentTimeMillis() - start) / + "s");
rafi.close();
rafo.close(); } // 3、BufferedInputStream&BufferedOutputStream: 3.02s
public static void BufferedInputStreamTest() throws Exception{
String srcFile = "F:\\Ebook\\偷天.txt";
String destFile = "F:\\Ebook\\toutian.txt";
FileInputStream rafi = new FileInputStream(srcFile);
FileOutputStream rafo = new FileOutputStream(destFile); BufferedInputStream bis = new BufferedInputStream(rafi, );
BufferedOutputStream bos = new BufferedOutputStream(rafo, );
long size = rafi.available(); long start = System.currentTimeMillis(); for (int i = ; i < size; i++) {
byte b = (byte) bis.read();
bos.write(b);
}
rafi.close();
rafo.close();
System.out.println("time: " + (double) (System.currentTimeMillis() - start) / + "s"); }
}

总结:

1、RandomAccessFile是Java输入输出流体系中功能最丰富的文件内容访问类,他提供 了众多的方法来访问文件,它既可以读取文件的内容,也可以说向文件输出数据,本身不带缓冲读写,和FileInputStream、FileOutputStream等一样,直接按字节读写时,性能不可接受;

2、使用MappedByteBuffer读写,固然性能会得到极大提升;其实只要自己处理缓冲,性能都会有非常大的提升,比如以下两种方式中第一种使用了MappedByteBuffer,第二种自己进行缓冲处理后,对于几兆的文件,后者的效率甚至高于前者,可以从几个size大小看出运行速度,当size较大的时候一次性的读取速度是慢些,但是整体的效率非常之高。

3、BufferedXXXX之类的缓冲流,如果仅使用默认的buffer size,性能不一定最优,要权衡不同情况各种因素设置大小。

MappedByteBuffer高速缓存文件、RandomAccessFile随机访问的更多相关文章

  1. [19/04/03-星期三] IO技术_其它流(RandomAccessFile 随机访问流,SequenceInputStream 合并流)

    一.RandomAccessFile 随机访问流 [版本1] /* *RandomAccessFile 所谓随机读取就是 指定位置开始或指定位置结束 的读取写入文件 * 实现文件的拆分与合并 模拟下载 ...

  2. Java I/O(三)各种Reader和Writer读写器、RandomAccessFile随机访问文件、序列化

    2019 01/01 八.Reader和Writer读写器 前面讲的输入输出流的基本单位都是字节,因此可以称为“字节流”,读写器是以字符为基本单位,可以称为“字符流”.它们的使用方法非常相似,因此我考 ...

  3. 18 IO流(十五)——RandomAccessFile随机访问文件及使用它进行大文件切割的方法

    本文部分内容转自:https://blog.csdn.net/nightcurtis/article/details/51384126 1.RandomAccessFile特点 RandomAcces ...

  4. JavaIO之RandomAccessFile随机访问文件

    package test.java.io; import java.io.RandomAccessFile; public class RandomAccFile { public static vo ...

  5. 系统学习 Java IO (四)----文件的读写和随机访问 FileInputStream/FileOutputStream & RandomAccessFile

    目录:系统学习 Java IO---- 目录,概览 文件输入流 FileInputStream 这是一个简单的FileInputStream示例: InputStream input = new Fi ...

  6. Java基础知识强化之IO流笔记63:随机访问流RandomAccessFile

    1. 随机访问流RandomAccessFile RandomAccessFile类不属于流,是Object类的子类.但它融合了InputStream和OutputStream的功能.支持对随机访问文 ...

  7. Java基础-IO流对象之随机访问文件(RandomAccessFile)

    Java基础-IO流对象之随机访问文件(RandomAccessFile) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.RandomAccessFile简介 此类的实例支持对 ...

  8. java 21 - 12 随机访问流(不属于IO流)

    随机访问流: RandomAccessFile类不属于流,是Object类的子类. 但它融合了InputStream和OutputStream的功能. 支持对文件的随机访问读取和写入. public ...

  9. Java:IO流其他类(字节数组流、字符数组流、数据流、打印流、Properities、对象流、管道流、随机访问、序列流、字符串读写流)

    一.字节数组流: 类 ByteArrayInputStream:在构造函数的时候,需要接受数据源,而且数据源是一个字节数组. 包含一个内部缓冲区,该缓冲区包含从流中读取的字节.内部计数器跟踪 read ...

随机推荐

  1. Unity三种截屏方法(非自带API)

    者利用了三种表现形式: 1,选择截图路径的方法 2,直接截取截屏的方法 3,截取鼠标圈选区域. 上代码,: 第一种是调用.net的类库,需要引用System.Windows.Forms.dll,在As ...

  2. android如何建立数据库。(如何重写SQLiteOpenHelper)

    public class DBConnection extendsSQLiteOpenHelper{//继承SQLiteOpenHelper, public DBConnection(Context ...

  3. android market 选择

    通过Java包名直接定位到你的App http://market.android.com/details?id=<java包名>或者market://details?id=<java ...

  4. 深入理解Android 自定义attr Style styleable以及其应用

    相信每一位从事Android开发的猿都遇到过需要自己去自定义View的需求,如果想通过xml指定一些我们自己需要的参数,就需要自己声明一个styleable,并在里面自己定义一些attr属性,这个过程 ...

  5. Swift的闭包(二):捕获值

    闭包可以从定义它的上下文中捕获常量和变量. 在Swift中,捕获值最简单的例子是嵌套函数,举个例子: func makeIncrementer(forIncrement amount: Int) -& ...

  6. Effective C++ 总结(二)

    四.设计与声明          条款18:让接口容易被正确使用,不易被误用      理想上,如果客户企图使用某个接口而却没有获得他所预期的行为,这个代码不该通过编译:如果代码通过了编译,它的行为就 ...

  7. noip 2015 运输计划 (lca+二分)

    /* 95 最后一个点T了 qian lv ji qiong 了 没学过树剖 听chx听xzc说的神奇的方法 Orz 首先求出每个计划的路径长度 这里写的倍增 然后二分答案 对于每个ans 统计> ...

  8. 前后台使用ajax传list的时候,用value[] 获取值

    使用json进行前后台交互的时候,如果穿过来是的是list,可以通过value[index],(index表示的是下标) //加载新闻 function jzxw(){ $.ajax( { type ...

  9. windows7在局域网中无法映射驱动器问题解决

    昨天下班时闲的蛋疼,因电脑比较慢,因此在计算机的[系统配置中]的启动选项下对[启动项目]和[服务]做了误操作,导致在计算机重启之后声卡.显卡.网卡等许多服务禁用,更令人费解的是内网中断了连接,无法访问 ...

  10. sql - Invalid object name 'dbo.in$'

    这是我从excel导入的表,用查询的时候,不加前面部分的'dbo',能查出来,好像是owner的原因吧.