Java代码
package jTest; import java.io.IOException; import java.io.RandomAccessFile; /** * @author root * RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录, * 并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。 */ public class RandomAccessFileTest { public static void main(String[] args) throws IOException { RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw"); for (int i = 0; i < 10; i++) { // 写入基本类型double数据 rf.writeDouble(i * 1.414); } rf.close(); rf = new RandomAccessFile("rtest.dat", "rw"); // 直接将文件指针移到第5个double数据后面 rf.seek(5); // 覆盖第6个double数据 rf.writeDouble(47.0001); rf.close(); rf = new RandomAccessFile("rtest.dat", "r"); for (int i = 0; i < 10; i++) { System.out.println("Value " + i + ": " + rf.readDouble()); } rf.close(); } }
package jTest;
import java.io.*;
/**
* @author root
* @实现文件复制操作
*/
public class RandomAccessFileTest2 {
public static void main(String[] args) throws Exception {
RandomAccessFile file = new RandomAccessFile("file", "rw");
// 以下向file文件中写数据
file.writeInt(20);// 占4个字节
file.writeDouble(8.236598);// 占8个字节
file.writeUTF("这是一个UTF字符串");// 这个长度写在当前文件指针的前两个字节处,可用readShort()读取
file.writeBoolean(true);// 占1个字节
file.writeShort(395);// 占2个字节
file.writeLong(2325451l);// 占8个字节
file.writeUTF("又是一个UTF字符串");
file.writeFloat(35.5f);// 占4个字节
file.writeChar(‘a‘);// 占2个字节
file.seek(0);// 把文件指针位置设置到文件起始处
// 以下从file文件中读数据,要注意文件指针的位置
System.out.println("——————从file文件指定位置读数据——————");
System.out.println(file.readInt());
System.out.println(file.readDouble());
System.out.println(file.readUTF());
file.skipBytes(3);// 将文件指针跳过3个字节,本例中即跳过了一个boolean值和short值。
System.out.println(file.readLong());
file.skipBytes(file.readShort()); // 跳过文件中“又是一个UTF字符串”所占字节,注意readShort()方法会移动文件指针,所以不用加2。
System.out.println(file.readFloat());
// 以下演示文件复制操作
System.out.println("——————文件复制(从file到fileCopy)——————");
file.seek(0);
RandomAccessFile fileCopy = new RandomAccessFile("fileCopy","rw");
int len = (int)file.length(); // 取得文件长度(字节数)
byte[] b = new byte[len];
file.readFully(b);
fileCopy.write(b);
System.out.println("复制完成!");
}
}
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class LargeMappedFiles {
static int length = 0x8000000; // 128 Mb
public static void main(String[] args) throws Exception {
// 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。
FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel();
//注意,文件通道的可读可写要建立在文件流本身可读写的基础之上
MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
//写128M的内容
for (int i = 0; i < length; i++) {
out.put((byte) ‘x‘);
}
System.out.println("Finished writing");
//读取文件中间6个字节内容
for (int i = length / 2; i < length / 2 + 6; i++) {
System.out.print((char) out.get(i));
}
fc.close();
}
}
尽管映射写似乎要用到FileOutputStream,但是映射文件中的所有输出 必须使用RandomAccessFile,但如果只需要读时可以使用FileInputStream,写映射文件时一定要使用随机访问文件,可能写时要读的原因吧。
其实掌握MappedByteBuffer并不难,只要记住“三方三法三特性”(转自http://blog.csdn.net/mgoann/article/details/3345850)这句话就可以轻松搞定!MappedByteBuffer 只是一种特殊的 ByteBuffer ,即是ByteBuffer的子类。 MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存,后面说证明这一点)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。而且,与ByteBuffer十分类似,没有构造函数(你不可new MappedByteBuffer()来构造一个MappedByteBuffer),我们可以通过 java.nio.channels.FileChannel 的 map() 方法来获取 MappedByteBuffer 。其实说的通俗一点就是Map把文件的内容被映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据而无需操作的时候每次都通过I/O去物理硬盘读取文件,所以效率上有很大的提升!
三种方式:
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. 随时随地写入
package jTest; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; public class MapMemoryBuff { public static void main(String[] args) throws Exception { ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024); byte[] bbb = new byte[14 * 1024 * 1024]; File f = new File("test"); FileInputStream fis = new FileInputStream("test"); FileOutputStream fos = new FileOutputStream("outFile.txt"); FileChannel fc = fis.getChannel(); long timeStar = System.currentTimeMillis();// 得到当前的时间 //fc.read(byteBuf);// 1 读取 MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0,f.length()); long timeEnd = System.currentTimeMillis();// 得到当前的时间 System.out.println("Read time :" + (timeEnd - timeStar) + "ms"); timeStar = System.currentTimeMillis(); //fos.write(bbb);// 2 写入 mbb.flip(); timeEnd = System.currentTimeMillis(); System.out.println("Write time :" + (timeEnd - timeStar) + "ms"); fos.flush(); fc.close(); fis.close(); } }
输出结果:
Read time :28ms
把上面的程序的1换成MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 文件长度);
2换成mbb.flip();
输出结果:Read time :2ms
Write time :0ms
可见普通I/O和MappedByteBuffer是没法比的。另外在写入的时候花了0ms说明Map写入机制是根据你的更改量来决定,就是只保存修改部分的!
随机访问文件RandomAccessFile 与 内存映射文件MappedByteBuffer,布布扣,bubuko.com
随机访问文件RandomAccessFile 与 内存映射文件MappedByteBuffer
原文:http://blog.csdn.net/yechaodechuntian/article/details/24912897