说到高速缓存存储,处理读写文件,那就不得不说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. PHP Ctype函数(转)

    Ctype函数是PHP内置的字符串体测函数.主要有以下几种 ctype_alnum -- Check for alphanumeric character(s)检测是否是只包含[A-Za-z0-9] ...

  2. 从零开始学习jquery (二)

    前面我们了解到了如何获取使用jquery,下面我们主要看看jquery的一些语法.基本的语法 $(selector).action(). 美元符号定义 jQuery 选择符(selector)&quo ...

  3. 【IOS】关于CGTransform的几个动画

    1.CGTransform主要三大功能,平移(Translation).缩放(Scale).旋转(Rotate). 平移: self.imageView.transform = CGAffineTra ...

  4. html02表格的使用

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. C#_事件委托

    CarDealer类 事件发布程序 using System; using System.Collections.Generic; using System.Linq; using System.Te ...

  6. Java POI 导出excel表

    1.首先下载poi-3.6-20091214.jar,下载地址如下: http://download.csdn.net/detail/evangel_z/3895051 2.Student.java ...

  7. Android 笔记

    一.MTK Android version在文件下build/core/version_defaults.xml下定义. 二.Android 重新编译frameworks/base/core/res资 ...

  8. iOS学习笔记(十四)——打电话、发短信

    电话.短信是手机的基础功能,iOS中提供了接口,让我们调用.这篇文章简单的介绍一下iOS的打电话.发短信在程序中怎么调用. 1.打电话 [[UIApplication sharedApplicatio ...

  9. Java笔试知识总结(第一回)

  10. 设计模式C++实现(1)——工厂模式

    该文章转载自: http://blog.csdn.net/wuzhekai1985 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径.设计模式中运用了面向对象编程语言的重要特性:封装 ...