`

随机访问文件RandomAccessFile 与 内存映射文件MappedByteBuffer

 
阅读更多
RandomAccessFile

RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。

RandomAccessFile不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至不使用InputStream和OutputStream类中已经存在的任何功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。

基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream结合起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件。

只有RandomAccessFile才有seek搜寻方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。

RandomAccessFile的绝大多数功能,但不是全部,已经被JDK 1.4的nio的"内存映射文件(memory-mapped files)"给取代了,你该考虑一下是不是用"内存映射文件"来代替RandomAccessFile了。
Java代码
import java.io.IOException; 
import java.io.RandomAccessFile; 
 
public class TestRandomAccessFile { 
    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(); 
    } 
}  
内存映射文件

内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。
fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。

MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。
Java代码
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,写映射文件时一定要使用随机访问文件,可能写时要读的原因吧。

该程序创建了一个128Mb的文件,如果一次性读到内存可能导致内存溢出,但这里访问好像只是一瞬间的事,这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。这样你就可以很方便地修改超大型的文件了(最大可以到2 GB)。注意,Java是调用操作系统的"文件映射机制"来提升性能的。

  RandomAccessFile类的应用 收藏
/*
* 程序功能:演示了RandomAccessFile类的操作,同时实现了一个文件复制操作。
*/
package com.lwj.demo;

import java.io.*;

public class RandomAccessFileDemo {
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("复制完成!");
}
}

运行结果(同时生成相应的文件):

——————从file文件指定位置读数据——————
20
8.236598
这是一个UTF字符串
2325451
35.5
——————文件复制(从file到fileCopy)——————
分享到:
评论

相关推荐

    深入浅出MappedByteBuffer.pdf

    总结起来,MappedByteBuffer利用了操作系统级别的内存映射功能,实现了Java程序对大文件的高效访问,减少了系统开销,提升了程序性能。对于处理大量数据或大文件的Java应用,使用MappedByteBuffer是优化IO操作的一个...

    java读取大文件

    `RandomAccessFile`类提供了随机访问文件的能力,可以读写文件的任意位置。在这里,它与`FileChannel`一起使用,用于创建`MappedByteBuffer`。 4. **FileChannel**: `FileChannel`是`RandomAccessFile`的一个...

    java读取超大文本文件

    对于需要随机访问或文件特别大的情况,推荐使用`RandomAccessFile`和`FileChannel`的组合,特别是利用`MappedByteBuffer`进行内存映射文件读取。这种方式能够显著提高文件的读取速度,因为数据直接从磁盘映射到内存...

    java大文件读取-乔乐共享

    ### Java大文件读取技术详解 #### 一、引言 在进行数据处理时,经常会...内存映射文件适合随机访问较多且文件大小适中的场景;而分块读取则更加灵活,适用于任何大小的文件。开发者应根据实际需求选择最合适的方法。

    读大文件Java

    如果需要随机访问文件,`RandomAccessFile`是理想选择。它允许在文件的任何位置读写,适合处理大型数据文件。 4. **NIO(New IO)**: Java NIO(非阻塞I/O)提供了一种新的I/O模型,通过通道(Channel)和缓冲区...

    java io读取文件

    - 支持随机访问文件,适用于大数据文件的分块读写。 7. **NIO(非阻塞I/O)** - Java 1.4引入的NIO库,提供了一种基于通道(Channel)和缓冲区(Buffer)的I/O模型,支持选择器(Selector)进行多路复用,提高了...

    Java流和文件总结(二)

    文件通道(FileChannel)可以从FileInputStream, FileOutputStream或RandomAccessFile获取,支持随机访问文件。MappedByteBuffer允许将文件映射到内存,使得文件操作如同操作内存一样高效。 Java的IO库还提供了对象...

    java读取大文件简单实例

    - 文件映射通常更适合于连续的、顺序的读写操作,而非随机访问。如果需要频繁进行随机访问,可能需要考虑其他方法,如使用`FileChannel`的`transferTo()`和`transferFrom()`方法。 5. **优化策略** - 分块读写:...

    java全栈工程师-java io

    - **RandomAccessFile**:支持随机访问文件的某个位置进行读写。 #### 2. 网络IO - **Socket**:用于创建客户端连接。 - **ServerSocket**:用于服务器端接收客户端连接。 - **DatagramSocket/DatagramPacket**:...

    未完成的java_nio

    - **FileChannel**:用于文件读写,可以进行随机访问,支持映射到内存。 - **SocketChannel**:用于TCP网络通信,提供读写数据的接口。 - **ServerSocketChannel**:用于监听客户端的TCP连接请求,创建新的...

    读取Java文件到byte数组的三种方法(总结)

    `RandomAccessFile`提供了对文件的随机访问能力,可以用来读取文件内容到byte数组。 ```java public byte[] readFileByRandomAccessFile(String filePath) throws IOException { File file = new File(filePath); ...

    IBM-ETP-java培训10.Java IO.ppt

    10. **随机访问文件**:RandomAccessFile类提供对文件的随机访问能力,可以读写文件的任意位置。 11. **对象流与序列化**:Serializable接口用于标记一个类的对象可以被序列化。ObjectInputStream和...

    Java的io的应用

    9. **随机访问文件**: RandomAccessFile类提供了对文件进行随机读写的能力,可以定位到文件的任意位置进行读写操作。 10. **字符编码**: Java中的流默认使用平台默认的字符编码,但可以通过指定编码(如UTF-8)...

    java io 系列操作代码练习 Java学习资料

    2. 对于大文件,可以使用RandomAccessFile进行随机访问。 3. 使用FileChannel进行大文件的高效传输,如内存映射文件(MappedByteBuffer)。 六、网络IO Java IO也支持网络通信,如Socket和ServerSocket类,可用于...

    Java_Read_Write_File_Modules

    - **RandomAccessFile**:此类提供了对文件的随机访问能力,可以读写文件的任意位置,非常适合处理大文件。 6. **NIO(New I/O)** - **java.nio**包:从Java 1.4引入的新I/O模型,提供了通道(Channels)、缓冲...

    java实现pdf按页转换为图片

    * java.io.RandomAccessFile:用于随机访问文件 * java.nio.MappedByteBuffer:用于映射文件到内存 * com.sun.image.codec.jpeg.JPEGCodec:用于jpeg编码 * com.sun.image.codec.jpeg.JPEGEncodeParam:用于jpeg编码...

    Java_IO

    - RandomAccessFile类允许对文件进行随机访问,可以定位到文件的任意位置进行读写。 11. **管道流(Piped Streams)** - 管道流用于线程间的通信,例如,一个线程可以通过PipedOutputStream发送数据,另一个线程...

    ip地址库 很全的库

    // 随机文件访问类 private RandomAccessFile ipFile; // 内存映射文件 private MappedByteBuffer mbb; // 单一模式实例 private static volatile IPSeeker instance = null; // 起始地区的开始和结束...

Global site tag (gtag.js) - Google Analytics