Java RandomAccessFile用法

转载 2013年12月02日 19:45:34



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


 

内存映射文件

内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。
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.   
  5. public class LargeMappedFiles {  
  6.     static int length = 0x8000000// 128 Mb  
  7.   
  8.     public static void main(String[] args) throws Exception {  
  9.         // 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。  
  10.         FileChannel fc = new RandomAccessFile("test.dat""rw").getChannel();  
  11.         //注意,文件通道的可读可写要建立在文件流本身可读写的基础之上  
  12.         MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length);  
  13.         //写128M的内容  
  14.         for (int i = 0; i < length; i++) {  
  15.             out.put((byte'x');  
  16.         }  
  17.         System.out.println("Finished writing");  
  18.         //读取文件中间6个字节内容  
  19.         for (int i = length / 2; i < length / 2 + 6; i++) {  
  20.             System.out.print((char) out.get(i));  
  21.         }  
  22.         fc.close();  
  23.     }  
  24. }  


 

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

 

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

 

RandomAccessFile类的应用:

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


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



随机读写是相对顺序读写而言的,所谓随机读写,是指可以在任何时候将存取文件的指针指向文件内容的任何位置。假设存在一个文件尺寸为1024个字节的文件,如果按照顺序存取原则的话,我们只能采用类似于FileStream.read()或者FileReader.readLine()的方式来一段一段,或者一行一行地读取,在多数情况下,这样仿佛没有问题。但是,请考虑下面两个场景:

        数据不是整体传输,而是分块传输的:请注意,一般意义上的分块传输,数据块到达接收方(或者说被接收方接受下来)的顺序是不可预料的。一般的多线程下载软件(如网络蚂蚁),采取的做法都是启动多个线程分工抓取网络资源文件的不同分段,在此过程中,哪个数据块先被下载软件接受,那块数据后被接受,是不可预料的。

        在一个大文件中快速定位:有事,我们很明确自己想读取的内容唉整个文件中的位置,例如,在一个尺寸达到2GB的文件中读取第1024*1024个字节。

以上场景不是顺序存取所擅长的。自然,不是顺序存取完全无能为力,只是代价和效率令人难以接受。

在java中,随机读写是通过java.io.RandomAccessFile类实现的。以下代码片段以随机文件方式创建一个文件,指定其尺寸是1024kb:

  1. private void createFile(String filePath)throws IOException  
  2. {  
  3.       File newFile=new File(filePath);  
  4.       RandomAccessFile raf=new RandomAccessFile(newFile,"rw");  
  5.       raf.setLength(1024*1024);  
  6.       raf.close();  
  7. }  

RandomAccessFile类的核心价值在于RandomAccessFile.seek()方法,通过这个方法,可以任意地指定当前存取文件的指针位置。下面的代码片段实现功能:在filePath文件的finishedFileSize个字节后写入bytes字节数组中的realLength个字节的数据:

  1. private void writeIntoFIle(String filePath,byte[] bytes,int realLength,int finishedFileSize) throws IOException  
  2. {  
  3.     File newFile=new File(filePath);  
  4.     RandomAccessFile raf=new RandomAccessFile(newFIle,"rw");  
  5.    raf.seek(finishedFileSize);  
  6.    raf.write(bytes,0,realLength);  
  7.    raf.close();  
  8. }  

可以随时调用RandomAccessFile类的getFilePionter()方法,获取文件指针当前距离文件起始位置的偏移量。



转自:http://blog.csdn.net/zsmj_2011/article/details/7983877




java中IO流总结之五:RandomAccessFile类的用法总结

RandomAccessFile类直接继承Object类,但它是IO包中的成员,用于随机访问文件,进行读写操作。字符流和字节流只能按顺序对文件进行读和写。RandomAccessFile类内部封装了一...

Java RandomAccessFile用法(转载)

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

RandomAccessFile类的用法.doc

  • 2011年06月10日 01:25
  • 160KB
  • 下载

Java按行读取正在被动态写入的大文件实例--使用RandomAccessFile(1)

[like Sunday like rain] 1.适用场景 适用于正在被动态按行写入的大文件的读取和处理。 2.RandomAccessFile类主要方法 (1)length:获取当前文件的长度...

JAVA高级视频_IO输入与输出02、03 RandomAccessFile 学习笔记

http://writeblog.csdn.net/PostEdit.aspx?entryId=6155925先说说自己对随机文件的理解,所谓 的随机绝不等于数学上的随机,这里的随机是指游标所指的位置...

Java RandomAccessFile文件操作详解

简介: RandomAccessFile类可以对文件随机访问的操作,访问包括读和写操作。该类的读写是基于指针的操作。 RandomAccessFile对文件进行随机访问操作时有两个模式,一种是只读...
  • shf4715
  • shf4715
  • 2015年07月31日 06:38
  • 4995

java中的RandomAccessFile的用法

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

java中的RandomAccessFile的用法

Java的RandomAccessFile提供对文件的读写功能,与普通的输入输出流不一样的是RamdomAccessFile可以任意的访问文件的任何地方。这就是“Random”的意义所在。 Rand...
  • z_Dendy
  • z_Dendy
  • 2013年01月10日 12:46
  • 452

JAVA IO流RandomAccessFile随机读取

public class BufferreadDemo { static long n;//定义静态变量n为了记录每次读取的文件指针 //本文以从文件中读取字符串并转化为整形为例说明 publi...

Java-IO之RandomAccessFile

RandomAccessFile是随机访问(读写)的类,支持对文件随机访问的读取和写入,也可以从指定的位置读取和写入文件数据。RandomAccessFile虽然属于java.io包,但它不是Inpu...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java RandomAccessFile用法
举报原因:
原因补充:

(最多只允许输入30个字)