IO系列(四) - RandomAccessFile 类解读

一、摘要

RandomAccessFile 类,也被称为随机访问文件类

RandomAccessFile 可以说是 Java 体系中功能最为丰富的文件操作类,相比之前介绍的通过字节流或者字符流接口方式读写文件,RandomAccessFile 类可以跳转到文件的任意位置处进行读写数据,而无需把文件从头读到尾,但是该类仅限于操作文件,不能访问其他的 IO 设备,如网络、内存映像等。

所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用 RandomAccessFile 将是更好的选择

实际上,虽然RandomAccessFile类具备随机读写数据的功能,但是它既不是InputStream的子类,也不是OutputStream的子类,绝大部分的方法都是从零开始写的,这可能是因为 RandomAccessFile 需要在文件里面前后移动,它的行为与其它的 I/O 类有着根本性的不同,所以相对比较独立。

RandomAccessFile对象类中内置了一个位置指示器,可以指向当前读写处的位置,当读写 n 个字节后,文件指示器将指向这 n 个字节后的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,当移动文件指示器到新的位置时,随后的读写将从新的位置开始,这是它与其他的文件读写方式最大的不同。

基本上,RandomAccessFile的工作方式是,结合DataInputStreamDataOutputStream类完成数据的读写,再加上自己的一些方法,比如定位用的 getFilePointer方法,在文件里移动用的seek方法,以及判断文件大小length方法、跳过多少字节数的skipBytes方法等,来完成文件的随机访问和读写操作。

具体怎么使用呢,我们一起来看看!

二、RandomAccessFile 类基本介绍

下面先来看看一个简单的例子。

// 获取随机访问文件对象
RandomAccessFile raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {// 写入数据,1个int占4个字节raf.writeInt(i);
}
raf.close();System.out.println("================修改前的内容===============" );
// 重新获取随机访问文件对象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {System.out.println("Value:" + i + ": " + raf.readInt());
}
raf.close();// 重新获取随机访问文件对象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
// 设置文件指针偏移量,从0开始,直接将文件指针移到第6个int数据后面(1个int占4个字节)
raf.seek(5 * 4);
//覆盖第6个int数据
raf.writeInt(16);
raf.close();System.out.println("================修改后的内容===============" );
// 重新获取随机访问文件对象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {System.out.println("Value:" + i + ": " + raf.readInt());
}
raf.close();

输出结果:

================修改前的内容===============
Value:0: 0
Value:1: 1
Value:2: 2
Value:3: 3
Value:4: 4
Value:5: 5
Value:6: 6
Value:7: 7
Value:8: 8
Value:9: 9
================修改后的内容===============
Value:0: 0
Value:1: 1
Value:2: 2
Value:3: 3
Value:4: 4
Value:5: 16
Value:6: 6
Value:7: 7
Value:8: 8
Value:9: 9

RandomAccessFile类为用户提供了两种构造方法,具体操作方式如下:

// 第一种构造方法:指定 file 对象和读写模式
RandomAccessFile raf = new RandomAccessFile(File file, String mode);// 第二种构造方法:指定 filename 路径和读写模式
RandomAccessFile raf = new RandomAccessFile(String filename, String mode);

其实第二种构造方法也是new File()出来,再调用第一种构造方法,两者都可以获取随机访问文件对象。

至于mode,表示以何种方式打开文件,Java给开发者提供了四种mode值,具体解释如下!

值得注意的地方是,"rw"模式下,Java 并不强求指定的路径下一定存在某个文件,假如文件不存在,会自动创建

RandomAccessFile类为用户提供的方法比较多,我们可以关注下几个重要的方法即可,详细方法如下图!

方法的使用,可以参考如下样例:

RandomAccessFile file = new RandomAccessFile("file.txt", "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.txt","rw");
int len=(int)file.length();//取得文件长度(字节数)
byte[] b=new byte[len];
file.readFully(b);//读取全部内容
fileCopy.write(b);//全部写入目标文件
System.out.println("复制完成!");

根据以上的方法介绍,我们可以利用RandomAccessFile实现一个在任意位置插入数据的操作,具体实例如下:

public class RandomAccessFileTest1 {/*** 插入数据* @param skip 跳过多少过字节进行插入数据* @param str 要插入的字符串* @param fileName 文件路径*/public static void insert(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();}}/*** 方法测试* @param args* @throws Exception*/public static void main(String[] args) {insert(0, "一起学习Java", "test.txt");insert(0, "Hello,", "test.txt");}
}

文件内容结果如下:

Hello,一起学习Java

三、RandomAccessFile 类的应用

在实际的开发过程中,RandomAccessFile 的一个重要应用场景就是网络请求中的文件多线程下载及断点续传。

首先将文件分成几块,然后每块用不同的线程进行下载,下面是一个利用多线程在写文件时的例子:

public class RandomAccessFileTest2 {public static void main(String[] args) throws Exception {// 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件RandomAccessFile raf = new RandomAccessFile("test.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字节之后开始写入数据}
}class FileWriteThread extends Thread{private int skip;private byte[] content;public FileWriteThread(int skip,byte[] content){this.skip = skip;this.content = content;}@Overridepublic void run(){RandomAccessFile raf = null;try {// 利用线程在文件的指定位置写入指定数据raf = new RandomAccessFile("test.txt", "rw");raf.seek(skip);raf.write(content);} catch (Exception e) {e.printStackTrace();} finally {try {raf.close();} catch (Exception e) {}}}
}

四、小结

本文主要围绕 RandomAccessFile 类的基本概念和常用方法,做了一次简单的知识总结,该类是 IO 流体系中功能最丰富的文件内容访问类,既可以读取文件中任意位置的内容,也可以向文件任意位置写入数据。

当然 RandomAccessFile 当读写大文件的时候,会出现内存溢出问题,此时可以采用内存映射文件方式进行读写数据,关于技术会在后期的文章中进行介绍。

内容难免有所遗漏,欢迎网友留言指出!

五、参考

1、博客园 - 五月的仓颉 - RandomAccessFile

2、csdn - akon_vm - Java RandomAccessFile用法

六、写到最后

最近无意间获得一份阿里大佬写的技术笔记,内容涵盖 Spring、Spring Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL 等技术知识。需要的小伙伴可以点击如下链接获取,资源地址:技术资料笔记。

不会有人刷到这里还想白嫖吧?点赞对我真的非常重要!在线求赞。加个关注我会非常感激!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704720.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【线性系统理论】笔记三

能控性判别 约当标准型 总结&#xff1a; 秩的判据 能观性判别 秩判据 能控Ⅰ型&能控Ⅱ型 1型 2型 能控性分解&能观型分解

dhcp(接口和全局地址池模式)

接口地址池和全局地址池 dhcp应用 1.全部开启dhcp功能 2.ar5 0口接口地址池 1口全局地址池 3.ar6和ar7配置&#xff0c;查看能否自动获取ip 左右不同两个网络&#xff0c;接口和全局地址池的区别 部分截图 ar6 ar7 ar5

Java面试八股之LinkedHashMap和PriorityQueue的区别是什么

Java中LinkedHashMap和PriorityQueue的区别是什么 LinkedHashMap LinkedHashMap 是 HashMap 的一个子类&#xff0c;继承了 HashMap 的特性&#xff0c;并在此基础上添加了链表结构来维护元素的插入顺序。具体来说&#xff0c;LinkedHashMap 通过将每个条目&#xff08;entry…

嵌入式开发十四:按键输入实验

前面两个实验&#xff0c;我们介绍了 STM32F4 的 IO 口作为输出的使用&#xff0c;这一次&#xff0c;我们将向大家介绍如何使用 STM32F4 的 IO 口作为输入用。我们将利用板载的 4 个按键&#xff0c;来控制板载的两个 LED 的亮灭和蜂鸣器。通过本次的学习&#xff0c;你将了解…

维护表空间中的数据文件

目录 向表空间中添加数据文件 从表空间中删除数据文件 删除users表空间中的users02.dbf数据文件 对数据文件的自动扩展设置 Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 维护表空间中的数据文件主要包括向表空间中添…

踩坑小结:Linux安装python环境 、安装OpenSSL

一、查看python版本 查看发现&#xff0c;linux上自带了python&#xff0c;不过是2.x版本的。 二、下载python3 2.1 下载 www.python.org/downloads/s… 可在当前目录下找到相对应的版本或者最新版本下载 也可以直接下载 Python 3.10.4 下载完在服务器上选择一个目录存放…

C++动态内存管理 new、delete

目录 一、C中动态内存管理 1、new和delete操作内置类型 2、new和delete操作自定义类型 二、operator new和operator delete函数 三、operator new[]与operator delete[]函数 四、new和delete的实现原理 1、内置类型 2、自定义类型 1、new 2、delete 3、new T[N] 4、…

困惑点记录

【第十章 总结思考】CIM之我见 - 知乎

【Linux进程通信 —— 管道】

Linux进程通信 —— 管道 进程间通信介绍进程间通信的概念进程间通信的目的进程间通信的本质进程间通信的分类 管道什么是管道匿名管道匿名管道的原理pipe用fork来共享管道原理站在文件描述符角度-深度理解管道站在内核角度-管道本质管道读写规则管道的特点管道的四种特殊情况管…

短视频矩阵系统/源码----可视化剪辑技术独家开发

现阶段市面上大多矩阵软件都非常程序化且需要使用者具有较强的逻辑思维能力或剪辑经验&#xff0c;这使得一些个人、团队、企业在使用时无形中增加了学习成本&#xff0c;剪辑出来的效果大多不尽如人意&#xff0c;发出来的视频没有流量&#xff0c;根本达不到预期效果。 如何提…

表白成功率百分百的向女朋友表白网页源代码,向女友表白HTML源代码

表白成功率百分百的向女朋友表白网页源代码&#xff0c;向女友表白HTML源代码 效果&#xff1a; 完整代码下载地址&#xff1a;向女友表白HTML源代码 <!DOCTYPE html> <!--STATUS OK--> <html><head><meta http-equiv"Content-Type" c…

嵌入式学习-PWM输出比较

简介 PWM技术 输出比较框图介绍 定时器部分 比较器控制部分 输出控制部分 相关寄存器