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

[java] view plaincopy

  1. import java.io.IOException;
  2. import java.io.RandomAccessFile;
  3. public class TestRandomAccessFile {
  4. public static void main(String[] args) throws IOException {
  5. RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");
  6. for (int i = 0; i < 10; i++) {
  7. //写入基本类型double数据
  8. rf.writeDouble(i * 1.414);
  9. }
  10. rf.close();
  11. rf = new RandomAccessFile("rtest.dat", "rw");
  12. //直接将文件指针移到第5个double数据后面
  13. rf.seek(5 * 8);
  14. //覆盖第6个double数据
  15. rf.writeDouble(47.0001);
  16. rf.close();
  17. rf = new RandomAccessFile("rtest.dat", "r");
  18. for (int i = 0; i < 10; i++) {
  19. System.out.println("Value " + i + ": " + rf.readDouble());
  20. }
  21. rf.close();
  22. }
  23. }

内存映射文件

内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。

fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。

MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。

[java] view plaincopy

  1. import java.io.RandomAccessFile;
  2. import java.nio.MappedByteBuffer;
  3. import java.nio.channels.FileChannel;
  4. public class LargeMappedFiles {
  5. static int length = 0x8000000; // 128 Mb
  6. public static void main(String[] args) throws Exception {
  7. // 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。
  8. FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel();
  9. //注意,文件通道的可读可写要建立在文件流本身可读写的基础之上
  10. MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);
  11. //写128M的内容
  12. for (int i = 0; i < length; i++) {
  13. out.put((byte) ‘x‘);
  14. }
  15. System.out.println("Finished writing");
  16. //读取文件中间6个字节内容
  17. for (int i = length / 2; i < length / 2 + 6; i++) {
  18. System.out.print((char) out.get(i));
  19. }
  20. fc.close();
  21. }
  22. }

尽管映射写似乎要用到FileOutputStream,但是映射文件中的所有输出 必须使用RandomAccessFile,但如果只需要读时可以使用FileInputStream,写映射文件时一定要使用随机访问文件,可能写时要读的原因吧。

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

RandomAccessFile类的应用:

[java] view plaincopy

  1. /*
  2. * 程序功能:演示了RandomAccessFile类的操作,同时实现了一个文件复制操作。
  3. */
  4. package com.lwj.demo;
  5. import java.io.*;
  6. public class RandomAccessFileDemo {
  7. public static void main(String[] args) throws Exception {
  8. RandomAccessFile file = new RandomAccessFile("file", "rw");
  9. // 以下向file文件中写数据
  10. file.writeInt(20);// 占4个字节
  11. file.writeDouble(8.236598);// 占8个字节
  12. file.writeUTF("这是一个UTF字符串");// 这个长度写在当前文件指针的前两个字节处,可用readShort()读取
  13. file.writeBoolean(true);// 占1个字节
  14. file.writeShort(395);// 占2个字节
  15. file.writeLong(2325451l);// 占8个字节
  16. file.writeUTF("又是一个UTF字符串");
  17. file.writeFloat(35.5f);// 占4个字节
  18. file.writeChar(‘a‘);// 占2个字节
  19. file.seek(0);// 把文件指针位置设置到文件起始处
  20. // 以下从file文件中读数据,要注意文件指针的位置
  21. System.out.println("——————从file文件指定位置读数据——————");
  22. System.out.println(file.readInt());
  23. System.out.println(file.readDouble());
  24. System.out.println(file.readUTF());
  25. file.skipBytes(3);// 将文件指针跳过3个字节,本例中即跳过了一个boolean值和short值。
  26. System.out.println(file.readLong());
  27. file.skipBytes(file.readShort()); // 跳过文件中“又是一个UTF字符串”所占字节,注意readShort()方法会移动文件指针,所以不用加2。
  28. System.out.println(file.readFloat());
  29. //以下演示文件复制操作
  30. System.out.println("——————文件复制(从file到fileCopy)——————");
  31. file.seek(0);
  32. RandomAccessFile fileCopy=new RandomAccessFile("fileCopy","rw");
  33. int len=(int)file.length();//取得文件长度(字节数)
  34. byte[] b=new byte[len];
  35. file.readFully(b);
  36. fileCopy.write(b);
  37. System.out.println("复制完成!");
  38. }
  39. }

RandomAccessFile 插入写示例:

[java] view plaincopy

  1. /**
  2. *
  3. * @param skip 跳过多少过字节进行插入数据
  4. * @param str 要插入的字符串
  5. * @param fileName 文件路径
  6. */
  7. public static void beiju(long skip, String str, String fileName){
  8. try {
  9. RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
  10. if(skip <  0 || skip > raf.length()){
  11. System.out.println("跳过字节数无效");
  12. return;
  13. }
  14. byte[] b = str.getBytes();
  15. raf.setLength(raf.length() + b.length);
  16. for(long i = raf.length() - 1; i > b.length + skip - 1; i--){
  17. raf.seek(i - b.length);
  18. byte temp = raf.readByte();
  19. raf.seek(i);
  20. raf.writeByte(temp);
  21. }
  22. raf.seek(skip);
  23. raf.write(b);
  24. raf.close();
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }

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

[java] view plaincopy

  1. import java.io.FileNotFoundException;
  2. import java.io.IOException;
  3. import java.io.RandomAccessFile;
  4. /**
  5. * 测试利用多线程进行文件的写操作
  6. */
  7. public class Test {
  8. public static void main(String[] args) throws Exception {
  9. // 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件
  10. RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");
  11. raf.setLength(1024*1024); // 预分配 1M 的文件空间
  12. raf.close();
  13. // 所要写入的文件内容
  14. String s1 = "第一个字符串";
  15. String s2 = "第二个字符串";
  16. String s3 = "第三个字符串";
  17. String s4 = "第四个字符串";
  18. String s5 = "第五个字符串";
  19. // 利用多线程同时写入一个文件
  20. new FileWriteThread(1024*1,s1.getBytes()).start(); // 从文件的1024字节之后开始写入数据
  21. new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据
  22. new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据
  23. new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据
  24. new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据
  25. }
  26. // 利用线程在文件的指定位置写入指定数据
  27. static class FileWriteThread extends Thread{
  28. private int skip;
  29. private byte[] content;
  30. public FileWriteThread(int skip,byte[] content){
  31. this.skip = skip;
  32. this.content = content;
  33. }
  34. public void run(){
  35. RandomAccessFile raf = null;
  36. try {
  37. raf = new RandomAccessFile("D://abc.txt", "rw");
  38. raf.seek(skip);
  39. raf.write(content);
  40. } catch (FileNotFoundException e) {
  41. e.printStackTrace();
  42. } catch (IOException e) {
  43. // TODO Auto-generated catch block
  44. e.printStackTrace();
  45. } finally {
  46. try {
  47. raf.close();
  48. } catch (Exception e) {
  49. }
  50. }
  51. }
  52. }
  53. }
时间: 2024-12-21 12:52:36

Java RandomAccessFile用法的相关文章

Java RandomAccessFile用法(转)

原文链接:http://blog.csdn.net/akon_vm/article/details/7429245 RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和DataOutpu

Java RandomAccessFile用法 【转】

RandomAccessFile源地址:http://blog.csdn.net/akon_vm/article/details/7429245 RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件.RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和DataOutput接口

java RandomAccessFile类文件基本操作

RandomAccessFile类是java中仿C的文件操作方法,下面通过实例演示RandomAccessFile类对文件的基本操作,深入了解请查看Java API文档.(注:RandomAccessFile类大多不被采用) 上代码 import java.io.*; public class AccessFileDemo { public static void main(String[] args) { Student stu1=new Student("Zhang San",10

Java RMI 用法总结

RMI就是远程方法调用的简写.顾名思义,就是让一台机器上的对象调用另外一个机器上的对象.RMI的用法非常简单,首先是服务端定义一个接口(接口要扩展Remote接口),再实现这个接口(要扩展UnicastRemoteObject),再绑定到Naming静态类中.客户端通过Naming获取一个远程对象,就可以像普通的对象一样调用远程对象了.RMI中有个Stub类,它的作用就是代理服务器的接口对象,负责将方法的调用转换成网络请求发送给服务器,再从服务器返回对象进行解码.在JDK1.5中,Stub类会自

最全面的Java多线程用法解析

最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

Java ReadWriteLock 用法

对象的方法中一旦加入synchronized修饰,则任何时刻只能有一个线程访问synchronized修饰的方法.假设有个数据对象拥有写方法与读方法,多线程环境中要想保证数据的安全,需对该对象的读写方法都要加入 synchronized同步块. 这样任何线程在写入时,其它线程无法读取与改变数据:如果有线程在读取时,其他线程也无法读取或写入. 这种方式在写入操作远大于读操作时,问题不大,而当读取远远大于写入时,会造成性能瓶颈,因为此种情况下读取操作是可以同时进行的,而加锁操作限制了数据的并发读取.

Java RandomAccessFile 文件写入

public void mouseDown(MouseEvent e) { try{ //指定目标文件 RandomAccessFile F = new RandomAccessFile("F:\\test.txt","rw"); //检索文件长度 long filelength = F.length(); // String content = text.getText(); //指针指向最后一位 F.seek(filelength); F.writeBytes(

Java List 用法代码分析 非常详细

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

【转】java list用法示例详解

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