`

RandomAccessFile

    博客分类:
  • java
 
阅读更多
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

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

    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类的应用:
[java] view plaincopy

    /*
     * 程序功能:演示了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 插入写示例:
[java] view plaincopy

    /**
     * 
     * @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实现文件的多线程下载,即多线程下载一个文件时,将文件分成几块,每块用不同的线程进行下载。下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间,然后在所分配的空间中进行分块,然后写入:
[java] view plaincopy

    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) { 
                    } 
                } 
            } 
        } 
     
    } 


分享到:
评论

相关推荐

    使用RandomAccessFile流将一个文本文件读出,并导致写入到另一个文件当中。

    ### 使用RandomAccessFile流将一个文本文件读出并写入到另一个文件中的知识点解析 在Java编程语言中,`RandomAccessFile`类提供了一种非常灵活的方式来读取和写入文件。它支持随机访问,意味着我们可以直接跳转到...

    JAVA随机存储流(RandomAccessFile)的应用

    Java中的`RandomAccessFile`是一个非常重要的类,它允许我们以随机访问模式读写文件,这意味着我们可以自由地在文件的任何位置进行读写操作,而不仅仅是顺序地从头到尾处理文件。这个类提供了对文件内容进行高效定位...

    RandomAccessFile类的用法.doc

    RandomAccessFile类是Java I/O库中的一个重要组件,它提供了对文件进行随机访问的能力,这意味着你可以直接跳到文件的任意位置进行读写操作,而不仅仅局限于从头到尾的顺序访问。这个类非常适合处理大数据量的文件,...

    java的RandomAccessFile对文件进行读写操作

    Java中的`RandomAccessFile`类是用于处理文件的高级接口,它允许我们对文件进行随机访问,即在文件的任何位置进行读写操作,而不仅仅是从文件头开始顺序读写。这种能力使得`RandomAccessFile`在处理大文件或者需要...

    RandomAccessFile向文件中写入中文

    ### RandomAccessFile 向文件中写入中文 在Java编程中,经常需要处理文件操作,尤其是在涉及中文字符的写入时。本篇文章将详细介绍如何利用`RandomAccessFile`类正确地向文件中写入中文字符,并解释不同写入方法的...

    【IT十八掌徐培成】Java基础第16天-01.RandomAccessFile.zip

    本教程聚焦于Java中的`RandomAccessFile`类,这是Java I/O流体系中的一个重要部分,用于处理可以随机读写的数据文件。在Java基础学习的第16天,我们将深入探讨这个主题。 `RandomAccessFile`类在`java.io`包下,它...

    NIO_RandomAccessFile_多线程_按行读本地CSV文件(java==> google guava包ListenableFuture)

    NIO_RandomAccessFile_多线程读本地CSV文件(java==&gt; google guava包ListenableFuture) reader里有个main函数,更改文件路径后,直接运行即可

    RandomAccessFile随机文本,使用多线程处理

    RandomAccessFile随机文本,使用多线程处理复制文件

    基于RandomAccessFile文件分类的小程序

    【基于RandomAccessFile文件分类的小程序】是一款实用的工具,其主要功能是对指定文件夹内的文件进行分类。在实现这一功能的过程中,它依赖于`config.xml`配置文件,该文件用于设定分类规则,即哪些文件应该被归为同...

    RandomAccessFile 解决乱码

    ### RandomAccessFile 解决乱码 #### 背景与问题描述 在Java编程中,`RandomAccessFile` 类提供了一种方式来处理文件中的数据,允许程序随机访问文件的任何部分。但在处理中文或其他非ASCII字符时,可能会遇到乱码...

    RandomAccessFile的用法

    Java的`RandomAccessFile`类是Java I/O流体系中的一种特殊类型,它允许程序员以随机访问模式读取和写入文件。与传统的输入/输出流不同,`RandomAccessFile`可以任意位置开始读写,这使得它在处理大文件或需要定位到...

    体会RandomAccessFile

    ### RandomAccessFile 随机访问文件的使用体会 #### 一、RandomAccessFile简介 `RandomAccessFile`是Java中的一个类,位于`java.io`包中,它提供了对文件进行读写的能力,并且可以随机地定位到文件中的任何位置...

    RandomAccessFile(下).mp4

    RandomAccessFile(下).mp4

    JAVA文件操作——File 、 RandomAccessFile(上).mp4

    文件操作——File 、 RandomAccessFile(上).mp4

    randomaccessfile例子

    RandomAccessFile处理文件的案例

    使用RandomAccessFile递归修改文件

    因为使用其他文件流修改文件时是整体的替换,导致SVN上传上去后是整个文件都修改了,所以需要增量修改,这个demo是使用RandomAccessFile增量修改,只修改指定的行,很实用

    花1K内存实现高效I-O的RandomAccessFile类

    花1K内存实现高效I-O的RandomAccessFile类 自己搜搜这个关键字. 我主要是用来优化Android上多线程断点下载的写文件效率 RandomAccessFile是操作硬盘的,比操作内存的数据慢了几百万倍, 所有有人做出优化,我特上传...

    文件操作——File 、 RandomAccessFile(上).mp4

    文件操作——File 、 RandomAccessFile(上).mp4

    dnzyz.rar_RandomAccessFile_java 文件管理_文件操作

    在Java编程语言中,`RandomAccessFile`是一个强大的类,用于对文件进行随机访问和读写操作。这个类提供了一种高效的方式,让我们能够在文件的任何位置读取或写入数据,而不仅仅是从文件的开头顺序读取。下面将详细...

Global site tag (gtag.js) - Google Analytics