12.7 RandomAccessFile

1、RandomAccessFile介绍

RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输入流不同的是,RandomAccessFile支持“随机访问”的方式,程序可以直接跳转到文件的任意地方来读写数据。
RandomAccessFile既可以读文件,也可以写,所以它既包含完全类似于InputStream的三个read()方法,其用法和InputStream的三个read()方法完全一样,也包含完全类似于OutputStream得三个write()方法。除此之外RandomAccessFile还包含了一系列得readXxx()和WriteXxx()方法来完成输入、输出。

2、RandomAccessFile的记录指针

RandomAccessFile对象也包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由移动该记录指针,既可以向前移动,也可以向后移动。RandomAccessFile包含了如下两个方法来操作文件记录指针:
long getFilePointer():返回文件记录指针的当前位置。
void seek(long pos):将文件记录指针定位到pos位置。

3、RandomAccessFile的读写模式

RandomAccessFile类有两个构造器,其实这两个构造器基本相同,真是指定文件的形式不同而已:一个使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,该参数有如下四个值:

mode 说明
"r" 以只读方式打开指定文件。如果试图对该RandomAccessFile执行写入方法都将会抛出 IOException。
"rw" 以读取、写入方式打开指定文件。如果该文件尚不存在,则尝试创建该文件。
"rws" 以读取、写入方式打开指定文件。相对于对于 "rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd" 以读取、写入方式打开指定文件。对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。

4、实例演示

4.1 访问指定的中间部分数据

下面程序使用RandomAceessFile来访问指定的中间部分数据
有一个test.txt文件,内容如下

package section7;

import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileTest
{
    public static void main(String[] args)
    {
        try(
                var raf=new RandomAccessFile("src//section7//test","r")
                )
        {
            //获取RandomAceessFile对象文件指定所在得位置,初始位置为0
            System.out.println("RandomAceessFile对象文件指针初始位置:"+raf.getFilePointer());
            //移动raf的文件记录指针的位置
            raf.seek(5);
            var buff=new byte[1024];
            //用于保存实际读到的字节数
            var hasRead=0;
            //使用循环来重复取水
            while ((hasRead=raf.read(buff))>0)
            {
                //取出“竹筒”中的水滴(字节),将字节数组转换为字符串
                System.out.print(new String(buff,0,hasRead));
            }
        }
        catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }
}
"D:\IntelliJ IDEA 2019.2.4\jbr\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar=64661:D:\IntelliJ IDEA 2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath E:\Java\mysql-connector-java-8.0.13.jar;E:\Java\chap15\out\production\chap15 section7.RandomAccessFileTest
RandomAceessFile对象文件指针初始位置:0
一二三四五
fhijk六七八九十
Process finished with exit code 0

程序先创建了一个FileAccessFile对象,该对象以只读方式打开test.txt文件。raf.seek(5);将记录指针移到位置5,只读取后面的内容。

4.2 向指定文件追加内容

为了追加内容,程序应该先将记录指针移到文件最后,然后向文件中输出内容。
注:关于String类的getBytes()方法的使用。https://www.cnblogs.com/sbclmy/p/8944700.html

package section7;
import java.io.IOException;
import java.io.RandomAccessFile;
public class AppendContent
{
    public static void main(String[] args)
    {
        try(
                //以读、写方式打开一个RandomAccessFile对象
                var raf=new RandomAccessFile("src//section7//test","rw")
                )
        {
            //将记录指针移到test.txt文件的最后
            raf.seek(raf.length());
            raf.write("追加的内容!\r\n".getBytes());
        }
        catch (IOException ioe)
        {
            ioe.printStackTrace();
        }
    }
}

上面的程序中创建了一个RandomAccessFile对象, raf.seek(raf.length());将记录指针移动最后,接下来使用RandomAccessFile执行输出。
我们将看到test.txt文件的内容:

4.3 插入内容

RandomAccessFile依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容会覆盖文件中原有的内容。
如果需要向指定位置插入内容,程序需要先把插入点后面内容读入缓冲区,等将需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面

package section7;
import java.io.*;
public class InsertContent
{
    private static void insert(String fileName, long pos, String insertContent)
            throws IOException
    {
        var file=new File(".");
        var tmp = File.createTempFile("tmp", null, file);
        tmp.deleteOnExit();
        try (
                var raf = new RandomAccessFile(fileName, "rw");
                // 使用临时文件来保存插入点后的数据
                var tmpOut = new FileOutputStream(tmp);
                var tmpIn = new FileInputStream(tmp))
        {
            raf.seek(pos);
            // ------下面代码将插入点后的内容读入临时文件中保存------
            var bbuf = new byte[64];
            // 用于保存实际读取的字节数
            var hasRead = 0;
            // 使用循环方式读取插入点后的数据
            while ((hasRead = raf.read(bbuf)) > 0 )
            {
                // 将读取的数据写入临时文件
                tmpOut.write(bbuf, 0, hasRead);
            }
            // ----------下面代码插入内容----------
            // 把文件记录指针重新定位到pos位置
            raf.seek(pos);
            // 追加需要插入的内容
            raf.write(insertContent.getBytes("UTF-8"));
            // 追加临时文件中的内容
            while ((hasRead = tmpIn.read(bbuf)) > 0)
            {
                raf.write(bbuf, 0, hasRead);
            }
        }
    }
    public static void main(String[] args) throws IOException
    {
        insert("src//section7//poem", 43, "**插入的内容**");
    }
}

我们看到poem.txt文件的内容已经被修改:

posted @ 2020-05-01 23:44  小新和风间  阅读(165)  评论(0编辑  收藏  举报