• Java输入/输出之RandomAccessFile的功能和用法


            RandomAccessFile 是Java 输入/输出流体系中功能最丰富的文件内容访问类,它提供了很多方法来访问文件内容。它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile 支持 "随机访问" 的方式,即程序可以直接跳转到文件的任意位置来读写数据。所以如果只需要访问文件部分内容,而不是把文件从头读到尾,使RandomAccessFile 将是更好的选择。

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

    • long getFilePointer():返回文件记录指针的当前位置。
    • void seek(long pos):将文件记录指针定位到pos 位置。

            RandomAccessFile 的方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他 IO 节点。

            RandomAccessFile 既可以读文件,也可以写文件,所以它既包含了完全类似于InputStream 的三个read()方法,其用法和InputStream 的三个read()方法完全一样。也包含了完全类似于OutputStream 的三个write()方法,其用法和OutputStream 的三个write()方法完全一样。除此之外,RandomAccessFile 还包含了一系列的read.Xxx()和writeXxx()方法来完成输入、输出。

    提示:

           计算机里的"随机访问"是一个很奇怪的词,对于汉语而言,随机访问是具有不确定性的意思,如果按这种方式来理解"随机访问",那么就会对所谓的"随机访问"方式感到十分迷惑。

    实际上,"随机访问"是由Random和Access两个单词翻译而来,而Random 在英语里不仅有随机的意思,还有任意的意思——如果将Random 理解为任意的意思,那么就可以更好地理解Random Access 了,它应该是任意访问,而不是随机访问。因此,RandomAccessFile 的含义是可以自由访问文件的任意地方(与InputStream、Reader 需要依次向后读取相区分)。

            此外RAM(Random Access Memory,即内存),也是同样的道理。RAM 是可以自由访问任意存储点的存储器(与磁盘、磁带等需要寻道、倒带才可访问指定存储点等存储器相区分)。

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

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

    ✔下面程序使用了RandomAccessFile 来访问指定的中间部分数据。

    1. public static void main(String[] args) {
    2. // 创建一个RandomAccessFile对象,该对象只能读取文件内容,不能执行写入.
    3. try (RandomAccessFile raf = new RandomAccessFile(
    4. "C:\\Users\\Administrator\\Desktop\\test\\test.txt",
    5. "r")) {
    6. // 获取RandomAccessFile对象文件指针的位置,初始位置是0.
    7. System.out.println("RandomAccessFile的文件指针的初始位置: " + raf.getFilePointer());
    8. // 移动raf的文件记录指针的位置,程序将从3字节处开始读.
    9. raf.seek(3);
    10. // 创建数据缓冲区
    11. byte[] bbuf = new byte[5];
    12. // 用于保存实际读取的字节数
    13. int hasRead = 0;
    14. while ((hasRead = raf.read(bbuf)) > 0) {
    15. System.out.println(new String(bbuf, 0, hasRead));
    16. }
    17. } catch (IOException ex) {
    18. ex.printStackTrace();
    19. }
    20. }

    ✔下面程序示范了如何向指定文件后追加内容(为了追加内容,程序应该先将记录指针移动到文件最后,然后开始向文件中输出内容)。

    1. /**
    2. * 每运行一次该程序,就会向文件中追加一行"追加的内容!"字符串.
    3. */
    4. public static void main(String[] args) {
    5. // 以读、写方式创建一个RandomAccessFile对象
    6. try (RandomAccessFile raf = new RandomAccessFile("C:\\Users\\Administrator\\Desktop\\test\\out.txt", "rw")) {
    7. // 将文件记录指针移动到out.txt文件的最后
    8. raf.seek(raf.length());
    9. raf.write("追加的内容!\r\n".getBytes());
    10. } catch (IOException ex) {
    11. ex.printStackTrace();
    12. }
    13. }

    注意:

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

            下面程序实现了向指定文件、指定位置插入内容的功能。

    1. public class InsertContent {
    2. public static void main(String[] args) throws IOException {
    3. insert("InsertContent.java", 45, "插入的内容\r\n");
    4. }
    5. /**
    6. * 每次运行上面程序,都会看到向InsertContent.java中插入了一行字符串。
    7. */
    8. public static void insert(String fileName, long pos, String insertContent) throws IOException {
    9. File tmp = File.createTempFile("tmp", null);
    10. tmp.deleteOnExit();
    11. try (RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
    12. FileOutputStream tmpOut = new FileOutputStream(tmp);
    13. FileInputStream tmpIn = new FileInputStream(tmp)) {
    14. raf.seek(pos);
    15. // -----下面代码将插入点后的内容读入临时文件中保存-----
    16. byte[] bbuf = new byte[64];
    17. // 用于保存实际读取的字节数
    18. int hasRead = 0;
    19. // 使用循环方式读取插入点后的数据
    20. while ((hasRead = raf.read(bbuf)) > 0) {
    21. // 将读取的数据写入临时文件
    22. tmpOut.write(bbuf, 0, hasRead);
    23. }
    24. // -----下面代码用于插入内容-----
    25. // 把文件记录指针重新定位到pos位置
    26. raf.seek(pos);
    27. // 追加需要插入的内容
    28. raf.write(insertContent.getBytes());
    29. // 追加临时文件中的内容
    30. while ((hasRead = tmpIn.read(bbuf)) > 0) {
    31. raf.write(bbuf, 0, hasRead);
    32. }
    33. } catch (IOException e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. }

            上面程序中使用File 的createTempFile(String prefix, String suffix)方法创建了一个临时文件(该临时文件将在JVM 退出时被删除),用以保存被插入文件的插入点后面的内容。程序先将文件中插入点后的内容读入临时文件中,然后重新定位到插入点,将需要插入的内容添加到文件后面,最后将临时文件的内容添加到文件后面,通过这个过程就可以向指定文件、指定位置插入内容。

  • 相关阅读:
    4、paxos协议
    类与对象(下篇)
    pandas 中的两种数据结构:Series, DataFrame
    免费文档翻译-免费批量文档翻译软件推荐
    【K8S系列】Kubernetes 之kubectl 常用命令汇总
    【C++】类和对象(下)
    linux 进程组和会话和线程
    05-`Linux`的软件管理
    java计算机毕业设计无人驾驶汽车管理系统源程序+mysql+系统+lw文档+远程调试
    Docker部署前后端服务示例
  • 原文地址:https://blog.csdn.net/weixin_42051619/article/details/126513948