Java IO RandomAccessFile 任意位置读/写

随机读写类

RandomAccessFile的唯一父类是Object,与其他流父类不同。是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。

RandomAccessFile是不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至都没有用InputStream和OutputStream已经准备好的功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。

工作方式:

基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream粘起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件,从这一点上看,假如RandomAccessFile继承了DataInputStream,它也许会干得更好。

只有RandomAccessFile才有seek方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。

RandomAccessFile的绝大多数功能,如果不是全部的话,已经被JDK1.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) {
                    }
                }
            }
        }  

    }

时间: 2024-08-04 10:35:05

Java IO RandomAccessFile 任意位置读/写的相关文章

Java.io.RandomAccessFile

RandomAccessFile Java提供的对文件内容的访问,既可以读文件,也可以写文件.支持随机访问文件,可以访问文件的任意位置. 1)Java文件模型 在硬盘上的文件是byte byte byte存储的,是数据的集合. 2)打开文件 有两种模式 rw 读写  r 只读. RandomAccessFile randomAccessFile=new RandomAccessFile(file, "rw"); 文件指针,打开文件时指针在开头 pointer=0. 3)写方法 rand

Java——IO类,字节流读数据

body, table{font-family: 微软雅黑} table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;} th{border: 1px solid gray; padding: 4px; background-color: #DDD;} td{border: 1px solid gray; padding: 4px;} tr:nth-child(2n){background-co

java并发读&写文件

最近在看Brian Goetz 的<<Java并发实战>>,这本书有两个版本,电子工业出版社的译本很糟糕,建议使用机械工业出版社出版出版的书籍. 在看到第三四章的时候突然想到了多线程读写文件,同时遇到一些书中没有的问题 1, 如何保证组合对象的安全性? 2, 如何判断不变性的约束条件 3, 如何不通过synchronized关键字和锁进行同步处理? 下面是一段代码, 用来从source 读取数据,通过多线程写入target文件中 思路: 1, 如何read/write文件? 2,

Java—IO流 RandomAccessFile类

RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. java文件模型,在硬盘上的文件是byte byte byte存储的,是数据的集合 打开文件,有两种模式,"rw"读写."r"只读:RandomAccessFile raf = new RandomAccessFile(file, "rw");,文件指针,打开文件时指针在开头 point = 0; 写方法,

J2SE知识点归纳笔记(七)---Java IO Part 1:File类与RandomAccessFile类

J2SE知识点归纳笔记(七)---Java IO Part 1:File类与RandomAccessFile类                                                                 --转载请注明出处:coder-pig 本节引言: 兜兜转转,又回来写Java了,上一篇J2SE知识点归纳笔记(六)---Java常用类是上2014.4.14写的,时隔一年 又来重拾之前还没写完的系列了,前些天群里一个妹子反映她Java基础薄弱,然后抱怨在cs

RandomAccessFile java IO

1.写入字节 /** * java.io.RandomAccessFile * RAF是专门用来读写文件数据的API,其基于指针对文件任意位置进行读写. */ public class RafDemo1 { public static void main(String[] args) throws IOException { /* * 对当前目录下的raf.dat文件读写数据 */ RandomAccessFile raf = new RandomAccessFile("./raf.dat&qu

类 RandomAccessFile 在文件任意位置进行读写

public class RandomAccessFile extends Object implements DataOutput, DataInput, Closeable 此类同时实现了DataOutput和DataInput接口,此类的实例支持对随机访问文件的读取和写入.随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组.存在指向该隐含数组的光标或索引,称为文件指针:输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针.如果随机访问文件以读取/写入模式创建,则

[Java IO]01_File类和RandomAccessFile类

File类 File类是java.io包中唯一对文件本身进行操作的类.它可以进行创建.删除文件等操作. File类常用操作 (1)创建文件 可以使用 createNewFille() 创建一个新文件. 注意: Windows 中使用反斜杠表示目录的分隔符"\". Linux 中使用正斜杠表示目录的分隔符"/". 最好的做法是使用 File.separator 静态常量,可以根据所在操作系统选取对应的分隔符. (2)删除文件 可以使用 delete() 删除一个文件.

Java IO流 之 RandomAccessFile

http://www.verejava.com/?id=16994711024818 package com.randomaccessfile; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFil