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的用法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

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

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

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

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

  • 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 指定位置实现文件读取与写入

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

  • Java中IO流 RandomAccessFile类实例详解

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

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

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

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

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

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

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

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

  • Java中SimpleDateFormat用法详解

    public class SimpleDateFormat extends DateFormat SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text -> date)和标准化. SimpleDateFormat 允许以为日期-时间格式化选择任何用户指定的方式启动. 但是,希望用 DateFormat 中的 getTimeInstance. getDateInstance 或 getDateTime

  • Java中DecimalFormat用法详解

    我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供DecimalFormat类,帮你用最快的速度将数字格式化为你需要的样子.下面是一个例子: importjava.text.DecimalFormat; public class TestNumberFormat{ public static void main(String[]args){ doublepi=3.1415927; //圆周率 //取一位整数 System.out.println(newDecimalForm

  • java.text.DecimalFormat用法详解

    简要 DecimalFormat 的 pattern 都包含着 正负子 pattern ,例如 "#,##0.00;(#,##0.00)": /** * Created by Shuai on 2016/7/11. */ public class Main { public static void main(String[] args) { // 正值 BigDecimal bigDecimal = BigDecimal.valueOf(-12211151515151.541666);

  • java Beanutils.copyProperties( )用法详解

    这是一篇开发自辩甩锅稿~~~~ 昨天测试小姐姐将我的一个bug单重开了,emmmm....内心OS:就调整下对象某个属性类型这么简单的操作,我怎么可能会出错呢,一定不是我的锅!!but再怎么抗拒,bug还是要改的,毕竟晚上就要发版本了~~ 老老实实将我前天改的部分跟了一遍,恩,完美,没有任何的缺失~~but本应success的测试数据,接口返还的结果确实是false来着,那还是老老实实debug吧. 一步步跟下来,恩,多么顺畅,就说一定不是我的锅~~诶?不对不对,这里的ID值,为啥是null?传

  • Java String类用法详解

    一.简介 零碎知识点 extends Object implements serializable,Comparable< String >,charSequence String类表示字符串,所有字符串文字都是此类的对象 字符串是不变的,值在创建后无法更改 对象一旦声明则不可改变,改变的只是地址,原来的字符串还是存在的,并且产生垃圾 任何一个""都为字符串对象,无赋值则为匿名对象 用"+"拼接字符串尽量避免,一般用append+toString Str

  • Java Arrays.sort()用法详解

    Java的Arrays类中有一个sort()方法,该方法是Arrays类的静态方法,在需要对数组进行排序时,非常的好用. 但是sort()的参数有好几种,下面我就为大家一一介绍,这几种形式的用法. 1.Arrays.sort(int[] a) 这种形式是对一个数组的所有元素进行排序,并且是按从小到大的顺序. 举例如下: import java.util.Arrays; public class Main { public static void main(String[] args) { int

  • Java System.setProperty()用法详解

    /* * 设置指定键对值的系统属性 * setProperty (String prop, String value); *  * 参数: * prop - 系统属性的名称. * value - 系统属性的值.   *  * 返回: * 系统属性以前的值,如果没有以前的值,则返回 null. *  * 抛出:   * SecurityException - 如果安全管理器存在并且其 checkPermission 方法不允许设置指定属性. * NullPointerException - 如果

  • Java instanceof关键字用法详解及注意事项

    instanceof 严格来说是Java中的一个双目运算符,用来测试一个对象是否为一个类的实例,用法为: boolean result = obj instanceof Class 其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false. 注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,

  • Java Collection集合用法详解

    目录 1.集合的主要体系及分支 1.1Collection集合及实现类 2.List集合(List是带有索引的,所以多注意索引越界等问题) 2.1 List的实现类 3.Set集合 3.1HashSet(Set的实现类) 3.2TreeSet集合(Set的实现类) 4.集合的高频面试题 4.1Arraylist 与 LinkedList 异同 4.2ArrayList 与 Vector 区别 集合框架底层数据结构总结 1.Collection 1.集合的主要体系及分支 1.1Collection

随机推荐