`

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

  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 plain copy
  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 plain copy
  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 plain copy
  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 plain copy
  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. }  

 

分享到:
评论

相关推荐

    Java RandomAccessFile的用法详解

    下面小编就为大家带来一篇Java RandomAccessFile的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

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

    Java在文件任意位置写入数据可以使用RandomAccessFile方法来完成,下面看一个简单的示例就明白了

    RandomAccessFile的用法

    java api中的java.io.RandomAccessFile类实现文件的随机写入.

    Java的IO流讲解代码: File 类、RandomAccessFile 类、字节流(文件字节流、缓冲字节流、基本数据类型

    此代码资源的目标是提供简单易懂的示例代码,帮助读者深入理解Java IO流的概念和使用方法。通过研究这些代码示例,读者将能够了解如何使用不同类型的IO类来进行文件读写、字符流、字节流、网络传输等各种常见的IO...

    (超赞)JAVA精华之--深入JAVA API

    3.1 Log4j基本使用方法 3.2 Dom4j 使用简介 3.3 Java 语言的 XML 验证 API 3.4 hibernate的hello word 3.5 JavaMail(JAVA邮件服务)API详解 3.6 jxl.jar 包简介 3.7 Java与XML联合编程之SAX篇 3.8 Java与XML联合...

    Java开发详解.zip

    031202_【第12章:JAVA IO】_RandomAccessFile笔记.pdf 031203_【第12章:JAVA IO】_字节流与字符流笔记.pdf 031204_【第12章:JAVA IO】_字节-字符转换流笔记.pdf 031205_【第12章:JAVA IO】_内存操作流笔记.pdf ...

    JAVA基础课程讲义

    JAVA.IO包相关流对象用法总结(尚学堂1002班王鑫) 165 IO中其他常用类 165 File类 165 RandomAccessFile 166 思考作业 166 上机作业 166 提高课外作业 166 第九章 多线程技术 167 基本概念 167 程序 167 进程 167 ...

    疯狂JAVA讲义

    学生提问:当我们使用编译C程序时,不仅需要指定存放目标文件的位置,也需要指定目标文件的文件名,这里使用javac编译Java程序时怎么不需要指定目标文件的文件名呢? 13 1.5.3 运行Java程序 14 1.5.4 根据...

    JAVA SE学习精华集锦

    3.1 Log4j基本使用方法 119 3.2 Dom4j 使用简介 120 3.3 Java 语言的 XML 验证 API 138 3.4 hibernate的hello word 143 3.5 JavaMail(JAVA邮件服务)API详解 145 3.6 jxl.jar 包简介 150 3.7 Java与XML联合编程之...

    张孝祥Java就业培训教程.pdf

    在第二章中,全面地讲解Java的基本语法知识,对基本语法的讲解也不是泛泛而谈,而是在其中贯穿各种实际应用中的巧妙用法和注意事项。在第三章和第四章中,透彻系统地讲解了面向对象的思想和应用。在以后的章节中,用...

    Java复习题及答案

    2、main方法是Java Application程序执行的入口点,关于main方法的方法头以下哪项是合法的( )。 A、 public static void main() B、 public static void main(String[ ] args) C、 public static int main(String[ ...

    java初学者必看

    最近正在学习Java,也买了很多的有关Java方面的书籍,其中发现《跟我学Java》这本书,都的很不错啊,所以顺便拿电脑把这本书的目录敲了下来,与大家分享。尤其是那些和我一样初学Java的朋友们,看看哪一节对你有用,...

    Java程序设计和实战 新东方Java教程及源代码

    流的概述 流的分类 InputStream/OutputStream Reader/Writer 流的几种典型流向 RandomAccessFile的用法 Zip格式文件的压缩/解压 新东方java教程

    java 编程入门思考

    3.1 使用Java运算符 3.1.1 优先级 3.1.2 赋值 3.1.3 算术运算符 3.1.4 自动递增和递减 3.1.5 关系运算符 3.1.6 逻辑运算符 3.1.7 按位运算符 3.1.8 移位运算符 3.1.9 三元if-else运算符 3.1.10 逗号运算符 3.1.11 ...

    Java初学者入门教学

    3.1 使用Java运算符 3.1.1 优先级 3.1.2 赋值 3.1.3 算术运算符 3.1.4 自动递增和递减 3.1.5 关系运算符 3.1.6 逻辑运算符 3.1.7 按位运算符 3.1.8 移位运算符 3.1.9 三元if-else运算符 3.1.10 逗号运算符 3.1.11 ...

    java联想(中文)

    3.1 使用Java运算符 3.1.1 优先级 3.1.2 赋值 3.1.3 算术运算符 3.1.4 自动递增和递减 3.1.5 关系运算符 3.1.6 逻辑运算符 3.1.7 按位运算符 3.1.8 移位运算符 3.1.9 三元if-else运算符 3.1.10 逗号运算符 3.1.11 ...

    java程序设计实验指导代码

    14.5 实验4 用RandomAccessFile实现名片记录本 14.6 实验5 Zip的压缩和解压缩 第15章 网络编程 15.1 预备知识 15.2 实验1 操纵URL以访问网络资源 15.3 实验2 一个网络交互式汇率转换程序 15.4 实验3 基于TCP/IP...

    AIC的Java课程1-6章

     [*]知道使用RandomAccessFile类和seek方法随机存取文件。 机动时间和复习 2课时 &lt;br&gt; 考试 4课时  时间:120-150分钟;其余时间可用于答疑。  题目来源: 大纲...

Global site tag (gtag.js) - Google Analytics