IO系列(四) - RandomAccessFile 类解读

news2024/9/23 1:38:48

一、摘要

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;
    }

    @Override
    public 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.coloradmin.cn/o/1678495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

买了个彩票,哈哈哈哈哈。

买了个彩票-双色球&#xff0c;发现挺有意思的。 索性把双色球的所有期的中奖号码的数据都爬了下来&#xff0c;03至今&#xff0c;21年了。txt文本&#xff0c;6.5MB大小。 大家有啥好的建议&#xff0c;分析一下数据呢。

字节跳动在2024年春季火山引擎Force原动力大会上隆重推出了“豆包大模型”家族

此次大会以AI为主题&#xff0c;聚焦大模型的应用与发展&#xff0c;旨在引领AI技术的落地和推动各行各业的数字化转型。 字节跳动官网&#xff1a;https://www.bytedance.com/zh/ 豆包官网&#xff1a;https://www.doubao.com/chat/ 更多消息&#xff1a;https://heehel.co…

洗衣洗鞋店做小程序有什么优势?

互联网洗衣洗鞋小程序闪亮登场&#xff0c;想知道这款小程序有何魅力吗&#xff1f; 如今&#xff0c;众多商家纷纷推出预约上门洗鞋服务&#xff0c;&#x1f481;‍♀️并倾力打造洗鞋小程序&#xff0c;旨在拓展线上销售渠道。&#x1f31f;那么&#xff0c;这款洗鞋小程序究…

2025秋招Java还是c++?

一、我的编程经 说说我的编程经历&#xff0c;在C和Java之间我经历了几个阶段&#xff1a; 大学期间&#xff0c;我浅尝辄止地学习了一段时间的Java&#xff0c;但后来放弃了&#xff0c;开始学习C/C。本科毕业后&#xff0c;我选择攻读硕士学位&#xff0c;并一直专注于C的学…

3种深拷贝实现,你都知道吗?

目录&#xff1a; 1、JSON.parse 2、structuredClone 3、cloneDeep

冒险岛vcruntime140_1.dll无法继续执行代码要怎么处理?教你一键修复vcruntime140_1.dll

当你在玩着冒险岛的时候&#xff0c;突然弹出一个vcruntime140_1.dll无法继续执行代码&#xff0c;这时候你是不是一脸懵逼&#xff1f;不知道怎么去解决&#xff1f;其实不需要担心&#xff0c;这是一个小问题&#xff0c;vcruntime140_1.dll文件是一个非常常用的dll文件&…

企业架构系统之-IT系统建设如何做好技术选型

背景 近日有幸与行业同仁交流工作心得&#xff0c;在讨论中&#xff0c;他们提到一个平时工作当中我们都会遇到和经历的一个问题&#xff1a;作为架构师&#xff0c;在日常工作中应如何进行技术选型&#xff1f;面对众多框架和组件中&#xff0c;我们又应如何选择&#xff0c;…

【更新公告】AirtestIDE更新至1.2.17版本

本次更新为AirtestIDE、Airtest-Selenium库更新。 AirtestIDE更新至1.2.17版本&#xff0c;AirtestIDE内置库Airtest更新为1.3.3.1版本&#xff0c;Poco更新为1.0.94版本&#xff0c;主要支持了selenium4.0以上版本&#xff0c;ADB更换为41版本&#xff0c;Airtest新增点击和滑…

“网络安全新纪元:等保2.0的详细解读与实践”

网络安全等级保护基本要求》&#xff08;等保2.0&#xff09;于2019年6月发布&#xff0c;是我国网络安全等级保护制度的一项重要标准。等保2.0主要针对关键信息基础设施的网络安全保护&#xff0c;对数据安全和个人信息保护提出了更高的要求。本文将对等保2.0进行详细解读&…

Pytorch入门实战 P10-使用pytorch实现车牌识别

目录 前言 一、MyDataset文件 二、完整代码&#xff1a; 三、结果展示&#xff1a; 四、添加accuracy值 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 本周的学习内容是&#xff0…

【永洪BI】管理系统

管理系统模块包括系统设置、认证授权、日志管理、监控预警、资源部署、VooltDB管理、数据库管理、企业应用配置、系统检查、应用管理模块。 系统设置界面&#xff1a; 可以进行清除系统缓存、配置系统主题、配置系统邮箱、配置门户主页、配置权限管理系统、配置密码策略、配置…

端午佳节,品尝食家巷传统面点与黄米粽子礼盒

端午佳节&#xff0c;品尝食家巷传统面点与黄米粽子礼盒 在这个端午节来临之际&#xff0c;食家巷倾情推出一款别具特色的端午礼盒&#xff0c;将甘肃的传统面点与地方特色黄米粽子完美融合&#xff0c;为您带来一场美味与传统的邂逅。 这款礼盒以甘肃传统面点一窝丝、油饼和烤…

Python 渗透测试:子域名查询.

什么是 子域名查询. 子域名查询是指通过域名系统(DNS)查找某个域名下的子域名信息。子域名是域名层级结构中的一部分,位于主域名的下一级。子域名查询是网络安全评估和渗透测试中的一个重要步骤,可以帮助安全研究人员更好地了解目标系统的架构和潜在的安全隐患。但在进行子域名…

svn批量解锁

问题 svn对文件进行checkout之后&#xff0c;先进行lock&#xff0c;之后再去更改&#xff0c;最后进行Commit操作&#xff1b; 上述为我们通过svn管理代码的正常方式&#xff0c;但总会有其他现象发生&#xff1b; 如果我们非正常操作&#xff0c;批量锁所有的svn文件&#x…

Pencils Protocol 宣布再获合作伙伴 Galxe 的投资

近日&#xff0c;Scroll生态项目Penpad将品牌进一步升级为Pencils Protocol&#xff0c;全新升级后其不仅对LaunchPad平台进行了功能上的升级&#xff0c;同时其也进一步引入了Staking、Vault以及Shop等玩法&#xff0c;这也让Pencils Protocol的叙事方向不再仅限于LaunchPad&a…

刘邦的创业团队是沛县人,朱元璋的则是凤阳;要创业,一个县人才就够了

当人们回顾刘邦和朱元璋的创业经历时&#xff0c;总是会感慨他们起于微末&#xff0c;都创下了偌大王朝&#xff0c;成就无上荣誉。 尤其是我们查阅史书时&#xff0c;发现这二人的崛起班底都是各自的家乡人&#xff0c;例如刘邦的班底就是沛县人&#xff0c;朱元璋的班底是凤…

openlayers 热力图 天地图

openlayers 实现热力图 样式可调 在https://blog.csdn.net/qq_36287830/article/details/131844745?spm1001.2014.3001.5501基础上改进来的 最终样式 关键代码 如果你有数据可以不使用for循环 var blurInput document.getElementById("blur");var rediusInput do…

sa-token权限认证框架,最简洁,最实用讲解

查看源码&#xff0c;可知&#xff0c;sa sa-token框架 测试代码源码配置自动装配SaTokenConfigSaTokenConfigFactory SaManager工具类SaFoxUtilStpUtilSaResult StpLogic持久层定时任务 会话登录生成token创建account-session事件驱动模型写入tokenSaSessionSaCookieSaTokenDa…

如何使用AspectJ做切面,打印jar包中方法的执行日记

最近在工作中遇到一个redis缓存中的hash key莫名其妙被删除的问题&#xff0c;我们用了J2Cache&#xff0c;二级缓存用的是redis。hash key莫名其妙被删除又没有日志&#xff0c;就想到做一个切面在调用redis删除hash key的方法的时候&#xff0c;打印日志&#xff0c;并且把调…

揭秘SmartEDA魅力:为何众多学校青睐这款电路仿真软件?

在当今数字化、信息化的教育时代&#xff0c;电子电路仿真软件已成为电子学教学不可或缺的重要工具。其中&#xff0c;SmartEDA电路仿真软件以其强大的功能、用户友好的界面以及丰富的教育资源&#xff0c;赢得了众多学校的青睐。那么&#xff0c;究竟是什么原因让SmartEDA成为…