Java文件I/O处理之RandomAccessFile【随意存取文件】

news2024/9/28 20:14:08

Java语言有一个处理文件输入输出的RandomAccessFile类,既可以读取文件内容,也可以向文件输出数据。
RandomAccessFile类在国内的技术文档和书籍中都翻译为“随机访问文件”类,确实令人不解。
在中文中“随机”的意思:

  1. 不设任何条件,随意的。
  2. 顺应情势变化。

概率论中有一个术语“随机事件”,很明显,“随机”意味着不受人为控制的、不确定的。
把RandomAccessFile翻译为“随机访问文件”明显是词不达意的。因此,为了更贴合原意,本文中我们翻译为“随意存取文件”。
RandomAccessFile类的继承层次:
在这里插入图片描述

RandomAccessFile不属于基本输入输出流(I/O)结构层次的一部分,它直接继承自Object。除了其实现了DataInput以及DataOutput(这两者亦由DataInputStream和DataOutputStream实现)接口之外,它们与InputStream或者OutputStream并无直接关系。

RandomAccessFile拥有与其他I/O流类完全不同的行为。
RandomAccessFile 既可以读取文件内容,也可以向文件输出数据。同时,RandomAccessFile 支持“随意访问”的方式,程序可以直接跳转到文件的任意地方来读写数据。
RandomAccessFile类的有些功能类似于DataInputStream和DataOutputStream的组合使用,可直接读取各种基本数据类型的数据。

随意存取文件的行为在低层存储文件类似于一个大型字节数组。刚打开文件时文件指针位于文件头部;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针;反之,输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入到文件末尾之后的输出操作导致该数组的扩容。

  • 一、构造函数

RandomAccessFile有两个主要构造函数:

	RandomAccessFile(File file, String mode)
	RandomAccessFile(String name, String mode)

参数说明:
参数 file/name:指定要打开的文件,可以是一个 File 对象或者一个字符串的文件路径。
参数 mode:该参数指定RandomAccessFile的访问模式,一共有4种模式:
在这里插入图片描述

  • 二、功能特点

a. 随机访问
RandomAccessFile 最主要的特点是支持随意访问。与顺序读取的文件类不同,RandomAccessFile 允许你跳到文件的任何位置来读写数据。通过文件的指针位置的移动,可以实现灵活的操作。

刚打开文件时,文件指针指向文件头部。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。

b. 读写功能并存
它支持文件的读取和写入,通过移动文件指针,可以在文件的任何位置进行读写。这与其他I/O 输入输出流不同,其他流通常是单向的,只能顺序读或顺序写。

c. 文件内容修改
它允许修改文件的内容,当文件指针处于文件内部时,写入数据就可覆盖更新原来的文件内容。也可在文件尾部追加数据。

  • 三、 常用方法
  1. long getFilePointer():获取当前文件指针位置
  2. long length():获取文件长度
  3. getChannel():返回nio通信的文件通道FileChannel
  4. seek(long pos):文件指针定位。参数 pos:表示文件指针的位置。pos 从文件的开始位置计算,位置 0 表示文件的起始点,文件的尾是length()指定的位置。
  5. 读写文件的方法。读方法read()有很多种重载方法,同样地写方法write()也有对应的多种重载方法。
/***读取数据的重载方法***/
read():读取一个字节,返回的是 byte 类型数据(0255 之间的值),如果到达文件末尾,则返回 -1read(byte[] b):从文件中读取多个字节到字节数组 b 中。
read(byte[] b, int off, int len):可以用来从文件中读取数据到字节数组的指定位置,并读取指定的字节数
readInt()readLong()readDouble():可以分别读取 4 字节的整数、8 字节的长整数、8 字节的浮点数。

/***写入数据的重载方法***/
write(int b):写入一个字节到文件中。
write(byte[] b):将字节数组 b 写入文件。
write(byte[] b, int off, int len):写入部分字节数组。功能:将字节数组 b 中从偏移量 off 开始的 len 个字节写入文件。
writeInt(int v)writeLong(long v)writeDouble(double v):分别将 4 字节的整数、8 字节的长整数、8 字节的双精度浮点数写入文件。

按行读取数据的方法:
String readLine():从该文件中读取一行文本。
两个读写UTF-8编码数据文件的方法:
a. readUTF()方法:从文件读取 UTF-8 编码的字符串。此方法首先读取两个字节的长度信息,然后根据这个长度读取字符串的 UTF-8 字节。最后,这些字节被转换为 Java 字符串。这意味着当你使用 readUTF 方法读取字符串时,需要确保文件中的字符串是使用 writeUTF 方法写入的,这样它们之间的长度信息和编码方式才能保持一致。
b. writeUTF(String str)方法:将一个字符串以 UTF-8 编码写入文件。此方法首先写入两个字节的长度信息,表示字符串的 UTF-8 字节长度,然后写入 UTF-8 字节本身。

  1. setLength(long newLength):设置文件长度
  2. close():关闭文件
  • 四、RandomAccessFile的使用场景
    RandomAccessFile 非常适合以下几种场景:

a. 文件分块与合并
你可以利用 seek() 定位文件的任意部分,结合 read() 和 write() 方法,实现对大文件的分块操作。这种技术通常用于文件上传、下载等场景。

b. 日志文件
对于需要频繁追加数据的日志文件,RandomAccessFile 可以方便地在文件末尾写入新日志,而不需要重新读取或写入文件的其他部分。

c. 视频流、音频流的处理
在处理大文件(如视频、音频)时,RandomAccessFile 的随机访问功能非常重要,因为这些文件通常需要快速定位到某一帧进行处理,而不是顺序读取。

  • 五、一个有残疾的文件切割例子
    使用RandomAccessFile类读取文件,并将文件切割成若干个数据块。详见参考资料“如何使用Java语言实现文件分片上传和断点续传功能?”
    (网友的原始代码有BUG,问题多多)请看其代码:
// 创建RandomAccessFile对象
RandomAccessFile raf = new RandomAccessFile(file, "r");

// 计算数据块大小
long blockSize = file.length() / numThreads;
if (file.length() % numThreads != 0) {
    blockSize++;
}

// 切割文件并保存到磁盘
for (int i = 0; i < numThreads; i++) {
    long start = i * blockSize;
    long end = Math.min(start + blockSize, file.length());
    byte[] buff = new byte[(int) (end - start)];

    raf.seek(start);
    raf.read(buff);

    String path = savePath + File.separator + i + ".part";
    try (FileOutputStream fos = new FileOutputStream(path)) {
        fos.write(buff);
    }
}

上面的代码,有不少错误,我这里指出一处,读者可自行分析:图中if语句块明显“逻辑错误 ***思维混乱”
在这里插入图片描述
编写文件切割程序,还是有一点难度的。读者若有兴趣,可自行编写一个文件切割程序试试。

随意存取文件例程
下面我们给出一个随意存取文件测试例程,演示了文件的读取、中间插入和尾部追加三个功能。完整的实例代码:

/***
 * @author QiuGen
 * @description  随意存取文件测试
 * 例程:RandomAccessFileTest.java
 * @date 2024/9/28
 * ***/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
	static String MSG = "去年今日此门中,人面桃花相映红。人面不知何处去,桃花依旧笑春风。";
	/***从文件读数据信息***/
	public static void readData(String path) {
		long pos = 0;
		try (RandomAccessFile rFile=new RandomAccessFile(path, "r")){
			System.out.println("文件指针初始位置:"+rFile.getFilePointer());
			byte buf[] = new byte[8];
			int num = 0;
			while ((num=rFile.read(buf))>0) {
				System.out.print(new String(buf, 0, num));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/***文件中间追加数据信息***/
	public static void insertData(String path,String inf) {
		try (RandomAccessFile rFile=new RandomAccessFile(path, "rw");
			FileOutputStream fos = new FileOutputStream("D:/tmp");
			FileInputStream fis = new FileInputStream("D:/tmp")){
			long pos = (rFile.length()/4)*2; //计算插入位置
			rFile.seek(pos); //把文件指针定位到文件中间位置
			//下面的操作,把插入点后面的数据存放到临时文件tmp
			byte buf[] = new byte[8];
			int num = 0;
			while ((num=rFile.read(buf))>0) {//循环读取数据
				fos.write(buf, 0, num); //数据存入临时文件
			}
			/***插入追加数据信息inf***/
			rFile.seek(pos); //重新定位文件指针到插入点
			rFile.write(inf.getBytes()); //插入追加数据信息
			
			//下面的操作,把暂存在临时文件tmp中的数据写回文件中
			while ((num=fis.read(buf))>0) {//循环读取数据
				rFile.write(buf, 0, num); //数据写回文件
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/***往文件尾部追加数据***/
	public static void appendData(String path) {
		try (RandomAccessFile rFile=new RandomAccessFile(path, "rw")){
			rFile.seek(rFile.length()); //把文件指针定位到文件结尾处
			rFile.write(MSG.getBytes());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		String str = "陌上花开,可缓缓归矣。";
		String path = "D:/Temp/测试文件";
		RandomAccessFileTest.appendData(path); //创建文件
		RandomAccessFileTest.readData(path); //从文件读数据信息
		System.out.println("\n***向文件追加数据信息***");
		RandomAccessFileTest.insertData(path, str);//文件中间追加数据信息
		RandomAccessFileTest.readData(path); //从文件读数据信息
	}
}

运行测试结果如下:
在这里插入图片描述

参考资料:

1,Java IO流——RandomAccessFile(随机读写)
2,如何使用Java语言实现文件分片上传和断点续传功能?
3,RandomAccessFile详细总结
4,RandomAccessFile详解

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

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

相关文章

流量新密码?AI宠物定制写真在小红书爆火,有人搞了10W+

大家好&#xff0c;我是灵魂画师向阳 不知道大家发现没&#xff1f;消费者对于情感价值的需求猛增&#xff0c;宠物服务行业衍生出越来越多的“拟人化”新业态。 宠物摄影和写真成为宠物经济中的新兴行业&#xff0c;吸引了越来越多的摄影师和养宠人的关注。 一些摄影师和摄…

《开题报告》基于SSM框架的电影评论网站的设计与实现源码++学习文档+答辩讲解视频

开题报告 研究背景 随着互联网技术的飞速发展&#xff0c;网络已成为人们获取信息、交流思想、分享体验的重要平台。在电影产业蓬勃发展的今天&#xff0c;观众对于电影的选择不再仅仅依赖于传统的宣传渠道&#xff0c;而是更加倾向于通过在线平台了解影片内容、观看预告片、…

C++基础知识十

1.string尾插 在一个string类型的字符后面插入其它的字符可以用push_back和append&#xff0c;这俩个是常用的。 #include<iostream> using namespace std; int main() {string s1("hello");s1.push_back( );s1.push_back(w);s1.push_back(o);s1.push_back(r…

实施自动化测试的五个条件

摘要&#xff1a; 谈到什么是组成一次自动化测试的“恰当实施”经常会关注你需要用的工具&#xff0c;但是那仅仅是等式的一部分。巴斯 迪杰斯特拉详细说明了你需要考虑的其他四件事&#xff0c;他们如何致力于你的自动化测试的成功&#xff0c;以及关联到不能适当关注它们中任…

如何存储你需要的信息:变量——WEB开发系列42

变量是一种用于存储数据的基本工具。它允许我们在代码中给某个数据赋予一个名字&#xff0c;便于在后续的代码中引用、更新、甚至重新赋值。 一、什么是变量&#xff1f; 变量本质上是一个“容器”&#xff0c;它存储特定的信息或数据。你可以把变量想象成一个标签&#xff0c…

巧用switch-case消除条件判断

shigen坚持更新文章的博客写手&#xff0c;记录成长&#xff0c;分享认知&#xff0c;留住感动。个人IP&#xff1a;shigen 在之前的文章中&#xff0c;我们有提交消除if-else代码的方法&#xff1a; 结合HashMap与Java 8的Function和Optional消除ifelse判断巧用枚举消除逻辑判…

工控主板在工业控制中扮演什么角色

工控主板在工业控制中扮演着至关重要的角色&#xff0c;它是工业控制系统的核心组件&#xff0c;负责连接、控制和管理各种工业设备&#xff0c;实现自动化生产和智能化管理。具体来说&#xff0c;工控主板在工业控制中的作用可以归纳为以下几个方面&#xff1a; 一、核心控制…

MNIST手写数字数据集

数据集 官网链接失效&#xff0c;我找到数据集后&#xff0c;上传到码云&#xff0c;并在这里分享。 打开链接&#xff0c;进入如下目录&#xff0c;即可找到如下八个文件&#xff1a; 下面是一些可有可无的介绍。 Mnist数据集介绍 Mnist数据集包含70000张手写数字图片&#x…

IO(Reader/Writer)

1.Reader a.简介 i.是Java的IO库提供的另一种输入流。和InputStream的区别是&#xff1a;InputStream是字节流&#xff0c;以byte为单位&#xff0c;Reader是字符流&#xff0c;以char为单位。 ii.java.io.Reader是所有字符输入流的超类。 b.FileReader i.FileReader默认的编…

【Kubernetes】常见面试题汇总(四十三)

目录 98. kube-apiserver 和 kube-scheduler 的作用是什么&#xff1f; 99.您对云控制器管理器了解多少&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;…

甘肃辣椒油:舌尖上的热辣诱惑

&#x1f4a5;宝子们&#xff0c;今天必须要给你们安利甘肃食家巷的辣椒油&#x1f336;️&#xff01;✨甘肃辣椒油&#xff0c;那可是有着独特魅力的美食瑰宝&#x1f60d;。它以其鲜艳的色泽、浓郁的香气和醇厚的辣味&#xff0c;瞬间点燃你的味蕾&#x1f525;。&#x1f3…

关于聚类算法的一份介绍

在这篇文章中我将介绍无监督算法中“聚类”部分的知识&#xff0c;其中关于K均值聚类、层次聚类、密度聚类部分我将各附上一份实际运用的代码&#xff0c;而其余的像学习向量量化、高斯混合聚类部分则只是简单介绍下概念。 一、 关于聚类 首先我先简单介绍下聚类算法有关的东…

2024年7月大众点评温州美食店铺基础信息

在做一些城市分析、学术研究分析、商业选址、商业布局分析等数据分析挖掘时&#xff0c;大众点评的数据参考价值非常大&#xff0c;截至2024年7月&#xff0c;大众点评美食店铺剔除了暂停营业、停止营业后的最新数据情况分析如下。 温州餐饮美食店铺约6.5万家&#xff0c;有均…

CTF-SSH私钥泄露

CTF-SSH私钥泄露 一.信息探测--查看开放的服务--分析探测结果-- 探测大端口的信息 深入挖掘ssh信息![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6baf0b5de72d537c7093d3e2394d93cd.png#pic_center)解密ssh秘钥信息 工具&#xff1a;kali Linux 一.信息探测…

IO相关知识(Filter/序列化)

1.Filter模式 a.简介 i.直接使用继承&#xff0c;为各种InputStream附加更多功能&#xff0c;根本无法控制代码的复杂度&#xff0c;很快就会失控。 ii.为了解决依赖继承会导致子类数量失控的问题&#xff0c;JDK首先将InputStream分为两大类&#xff1a; …

SpringBoot+Activiti7工作流入门实例

目录 文章目录 目录准备Activiti建模工具1、BPMN-js在线设计器1.1 安装1.2 使用说明1.3运行截图 2、IDEA安装Activiti Designer插件2.1安装插件2.2 设置编码格式防止中文乱码2.3 截图 简单工作流入门实例1. 新建Spring Boot工程2. 引入Activiti相关依赖添加版本属性指定仓库添加…

10.1软件工程知识详解上

软件工程概述 软件开发生命周期 软件定义时期&#xff1a;包括可行性研究和详细需求分析过程&#xff0c;任务是确定软件开发工程必须完成的总目标&#xff0c;具体可分成问题定义、可行性研究、需求分析等。软件开发时期&#xff1a;就是软件的设计与实现&#xff0c;可分成…

一文上手SpringSecuirty【六】

自定义认证流程完成之后,前端收到了后端生成的token,那么在之后的所有请求当前,都必须携带token.作为服务器来说,得验证这个token,是否合法. 一、验证token是否合法 1.1 OncePerRequestFilter过滤器 OncePerRequestFilter是 Spring 框架中的一个过滤器&#xff0c;用于确保在…

强化-极限

不利于元素及时提现 要学会构建导数&#xff08;按照定义&#xff09;

老挝旅游如何解决沟通问题?《老挝语翻译通》app支持语音识别翻译功能,能有效解决语言不同的痛点

老挝&#xff0c;一个东南亚的神秘国度&#xff0c;以其独特的文化和语言吸引着全球旅行者和语言爱好者。为了帮助大家更好地了解和学习老挝语&#xff0c;我们推出了《老挝语翻译通》App&#xff0c;一款集翻译、学习、旅游于一体的多功能工具。 功能亮点 实时翻译&#xff1…