Java RandomAccessFile的用法详解

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了。

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 * 8);
    //覆盖第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( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。

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

RandomAccessFile 插入写示例:

/**
 *
 * @param skip 跳过多少过字节进行插入数据
 * @param str 要插入的字符串
 * @param fileName 文件路径
 */
public static void beiju(long skip, String str, String fileName){
  try {
    RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
    if(skip < 0 || skip > raf.length()){
      System.out.println("跳过字节数无效");
      return;
    }
    byte[] b = str.getBytes();
    raf.setLength(raf.length() + b.length);
    for(long i = raf.length() - 1; i > b.length + skip - 1; i--){
      raf.seek(i - b.length);
      byte temp = raf.readByte();
      raf.seek(i);
      raf.writeByte(temp);
    }
    raf.seek(skip);
    raf.write(b);
    raf.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

利用RandomAccessFile实现文件的多线程下载,即多线程下载一个文件时,将文件分成几块,每块用不同的线程进行下载。下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间,然后在所分配的空间中进行分块,然后写入:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile; 

/**
 * 测试利用多线程进行文件的写操作
 */
public class Test { 

  public static void main(String[] args) throws Exception {
    // 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件
    RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");
    raf.setLength(1024*1024); // 预分配 1M 的文件空间
    raf.close(); 

    // 所要写入的文件内容
    String s1 = "第一个字符串";
    String s2 = "第二个字符串";
    String s3 = "第三个字符串";
    String s4 = "第四个字符串";
    String s5 = "第五个字符串"; 

    // 利用多线程同时写入一个文件
    new FileWriteThread(1024*1,s1.getBytes()).start(); // 从文件的1024字节之后开始写入数据
    new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据
    new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据
    new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据
    new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据
  } 

  // 利用线程在文件的指定位置写入指定数据
  static class FileWriteThread extends Thread{
    private int skip;
    private byte[] content; 

    public FileWriteThread(int skip,byte[] content){
      this.skip = skip;
      this.content = content;
    } 

    public void run(){
      RandomAccessFile raf = null;
      try {
        raf = new RandomAccessFile("D://abc.txt", "rw");
        raf.seek(skip);
        raf.write(content);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } finally {
        try {
          raf.close();
        } catch (Exception e) {
        }
      }
    }
  } 

} 

以上这篇Java RandomAccessFile的用法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

时间: 2016-06-06

Java RandomAccessFile 指定位置实现文件读取与写入

Java RandomAccessFile 指定位置实现文件读取与写入 RandomAccessFile是属于随机读取类,是可以对文件本身的内容直接随机进行操作的,可以在文件的指定位置的读取和写入内容,这在很多时候都是很方便的. RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和Out

java使用randomaccessfile在文件任意位置写入数据

复制代码 代码如下: import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.RandomAccessFile; public class InsertContent {    public static void insert(String fileName, long pos, String inse

Java使用RandomAccessFile类对文件进行读写

1. RandomAccessFile类简介 前面一篇随笔<File类遍历目录及文件>中有说到,File类只能用于表示文件或目录的名称.大小等信息,而不能用于文件内容的访问.而当需要访问文件内容时,就可以用RandomAccessFile类了. RandomAccessFile是Java提供用来访问一些保存数据记录的文件的类,可以进行读取操作,也可以进行写入操作,写入的数据则以byte的形式存储:支持随机访问,也就是可以访问文件的任意位置(通过文件指针实现). 2. 构造函数 RandomAc

Java的字符读写类CharArrayReader和CharArrayWriter使用示例

CharArrayReader CharArrayReader 是字符数组输入流.它和ByteArrayInputStream类似,只不过ByteArrayInputStream是字节数组输入流,而CharArray是字符数组输入流.CharArrayReader 是用于读取字符数组,它继承于Reader.操作的数据是以字符为单位! CharArrayReader 函数列表: CharArrayReader(char[] buf) CharArrayReader(char[] buf, int

Java核心编程之文件随机读写类RandomAccessFile详解

本文实例为大家分享了Android九宫格图片展示的具体代码,供大家参考,具体内容如下 1.RandomAccessFile RandomAccessFile主要用于文件内容的读写访问 2.访问模式 "r":只读方式. "rw":打开以便读取和访问,如果文件不存在则创建文件. "rws": 除了'rw'功能以外,文件内容或者元数据更新时一同写入. "rwd":除了'rw'功能以外,文件内容更新时一同写入. 3.使用案例 pack

深入分析:用1K内存实现高效I/O的RandomAccessFile类的详解

主体:目前最流行的J2SDK版本是1.3系列.使用该版本的开发人员需文件随机存取,就得使用RandomAccessFile类.其I/O性能较之其它常用开发语言的同类性能差距甚远,严重影响程序的运行效率.开发人员迫切需要提高效率,下面分析RandomAccessFile等文件类的源代码,找出其中的症结所在,并加以改进优化,创建一个"性/价比"俱佳的随机文件访问类BufferedRandomAccessFile.在改进之前先做一个基本测试:逐字节COPY一个12兆的文件(这里牵涉到读和写)

Java中IO流 RandomAccessFile类实例详解

Java中IO流 RandomAccessFile类实例详解 RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. java文件模型,在硬盘上的文件是byte byte byte存储的,是数据的集合 打开文件,有两种模式,"rw"读写."r"只读:RandomAccessFile raf = new RandomAccessFile(file, "rw");,文

RandomAccessFile简介_动力节点Java学院整理

RandomAccessFile RandomAccessFile 是随机访问文件(包括读/写)的类.它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据. 需要注意的是,RandomAccessFile 虽然属于java.io包,但它不是InputStream或者OutputStream的子类:它也不同于FileInputStream和FileOutputStream. FileInputStream 只能对文件进行读操作,而FileOutputStream 只能对文件进

Nginx简介_动力节点Java学院整理

1.什么是Nginx Nginx来自俄罗斯的Igor Sysoev在为Rambler Media(http://www.rambler.ru/)工作期间,使用C语言开发了Nginx.Nginx作为Web服务器,一直为俄罗斯著名的门户网站Rambler Media提供着出色.稳定的服务. Igor Sysoev将Nginx的代码开源,并且赋予其最自由的2-clause BSD-like license许可证.由于Nginx使用基于事件驱动的架构能够并发处理百万级别的TCP连接,高度模块化的设计和自

Java Map简介_动力节点Java学院整理

Map简介 将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值.此接口取代 Dictionary 类,后者完全是一个抽象类,而不是一个接口. Map 接口提供三种collection 视图,允许以键集.值集或键-值映射关系集的形式查看某个映射的内容.映射顺序 定义为迭代器在映射的 collection 视图上返回其元素的顺序.某些映射实现可明确保证其顺序,如 TreeMap 类:另一些映射实现则不保证顺序,如HashMap 类. 注:将可变对象用作映射键时必须格外小心.当对

Java中Object toString方法简介_动力节点Java学院整理

一.Object类介绍  Object类在Java里面是一个比较特殊的类,JAVA只支持单继承,子类只能从一个父类来继承,如果父类又是从另外一个父类继承过来,那他也只能有一个父类,父类再有父类,那也只能有一个,JAVA为了组织这个类组织得比较方便,它提供了一个最根上的类,相当于所有的类都是从这个类继承,这个类就叫Object.所以Object类是所有JAVA类的根基类,是所有JAVA类的老祖宗.所有的类,不管是谁,都是从它继承下来的. 二.toString方法介绍  一个字符串和另外一种类型连接

Java Set简介_动力节点Java学院整理

1. 概述   Java 中的Set和正好和数学上直观的集(set)的概念是相同的.Set最大的特性就是不允许在其中存放的元素是重复的.根据这个特点,我们就可以使用Set 这个接口来实现前面提到的关于商品种类的存储需求.Set 可以被用来过滤在其他集合中存放的元素,从而得到一个没有包含重复新的集合. 2. 常用方法 按照定义,Set 接口继承 Collection 接口,而且它不允许集合中存在重复项.所有原始方法都是现成的,没有引入新方法.具体的 Set 实现类依赖添加的对象的 equals()

Java字符编码简介_动力节点Java学院整理

1. 概述 本文主要包括以下几个方面:编码基本知识,Java,系统软件,url,工具软件等. 在下面的描述中,将以"中文"两个字为例,经查表可以知道其GB2312编码是"d6d0 cec4",Unicode编码为"4e2d 6587",UTF编码就是"e4b8ad e69687".注意,这两个字没有iso8859-1编码,但可以用iso8859-1编码来"表示". 2. 编码基本知识 最早的编码是iso88

Java7之forkjoin简介_动力节点Java学院整理

Java7引入了Fork Join的概念,来更好的支持并行运算.顾名思义,Fork Join类似与流程语言的分支,合并的概念.也就是说Java7 SE原生支持了在一个主线程中开辟多个分支线程,并且根据分支线程的逻辑来等待(或者不等待)汇集,当然你也可以fork的某一个分支线程中再开辟Fork Join,这也就可以实现Fork Join的嵌套. 有两个核心类ForkJoinPool和ForkJoinTask. ForkJoinPool实现了ExecutorService接口,起到线程池的作用.所以

Java List简介_动力节点Java学院整理

Java中可变数组的原理就是不断的创建新的数组,将原数组加到新的数组中,下文对Java List用法做了详解.  List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引  ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步  LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快)  Vector:底层是数组数据结构 线

jQuery Autocomplete简介_动力节点Java学院整理

jQuery UI Autocomplete是jQuery UI的自动完成组件,是我用过的最强大.最灵活的Autocomplete,它支持本地的Array/JSON数组.通过ajax请求的Array/JSON数组.JSONP.以及Function(最灵活)等方式来获取数据. 支持的数据源 jQuery UI Autocomplete主要支持字符串Array.JSON两种数据格式. 普通的Array格式没有什么特殊的,如下: ["bjpowernode","动力节点"

JDBC简介_动力节点Java学院整理

前言:什么是JDBC 维基百科的简介: Java 数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法.JDBC也是Sun Microsystems的商标.它JDBC是面向关系型数据库的. 简单地说,就是用于执行SQL语句的一类Java API,通过JDBC使得我们可以直接使用Java编程来对关系数据库进行操作.通过封装,可以使开发人员使用纯Java API完成S