深入理解JAVA I/O系列四:RandomAccessFile
一、简述

这个是JDK上的截图,我们可以看到它的父类是Object,没有继承字节流、字符流家族中任何一个类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。
二、存在的意义
1、是JAVA I/O流体系中功能最丰富的文件内容访问类,它提供了众多方法来访问文件内容。
2、由于可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,RandomAccessFile将是更好的选择。
3、可以用来访问保存数据记录的文件,文件的记录的大小不必相同,但是其大小和位置必须是可知的。
这个类在很多资料上翻译成中文都是:随机访问文件,在中文里,随机是具有不确定的含义,指一会访问这里,一会访问那里的意思。如果以这种语义来解释的话,就会感到很困惑。其实,Random在英文中不仅仅有随机,还有任意的意思。如果中文名为任意访问文件是不是就会更好的理解。任意表示我们可以指定文件中任何一个位置去操作一个文件。
三、DEMO演示
(1)、写入文件
public class RandomAccessFileTest
{
public static void main(String[] args) throws IOException
{
RandomAccessFile raf = new RandomAccessFile("d:/data.txt","rw");
Person p = new Person(1001,"xiaoming",1.80d);
p.write(raf);
}
}
class Person
{
int id;
String name;
double height;
public Person()
{
}
public Person(int id, String name, double height)
{
this.id = id;
this.name = name;
this.height = height;
} public void write(RandomAccessFile raf) throws IOException
{
raf.write(id);
raf.writeUTF(name);
raf.writeDouble(height);
}
}
执行结果:

1、执行结果乱码是由于写入的是二进制文件,这个待会我们再使用程序读取。(这个跟前面介绍的DataInputStream、DataOutputStream类似)
2、第五行中,RandomAccessFile的构造函数除了指定了要写入了文件,还有另外一个参数:mod,主要用来指定打开文件的访问模式。

3、读取的方式就是读取基本数据类型,其中第28行使用的方法是:writeUTF(String str)
使用 modified UTF-8 编码以与机器无关的方式将一个字符串写入该文件,这个方法就是将字符串写入文件,而且不用担心会出现乱码,因为使用的编码方式是UTF-8
(2)、文件读取
由于刚才写入的是二进制文件,现在使用程序去读取文件:
public class RandomAccessFileTest
{
public static void main(String[] args) throws IOException
{
RandomAccessFile raf = new RandomAccessFile("d:/data.txt", "rw");
Person p = new Person(1001, "xiaoming", 1.80d);
p.write(raf);// 写入文件后,任意访问文件的指针在文件的结尾 raf.seek(0);// 读取时,将指针重置到文件的开始位置。
Person p2 = new Person();
p2.read(raf);
System.out.println("id=" + p2.getId() + ";name=" + p2.getName()
+ ";height=" + p2.getHeight()); }
}
class Person
{
int id;
String name;
double height;
public Person()
{
}
public Person(int id, String name, double height)
{
this.id = id;
this.name = name;
this.height = height;
} public void write(RandomAccessFile raf) throws IOException
{
raf.writeInt(id);
raf.writeUTF(name);
raf.writeDouble(height);
} public void read(RandomAccessFile raf) throws IOException
{
this.id = raf.readInt();
this.name = raf.readUTF();
this.height = raf.readDouble();
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public double getHeight()
{
return height;
}
public void setHeight(double height)
{
this.height = height;
} }
执行结果:
id=1001;name=xiaoming;height=1.8
1、在39-43行代码中,由于是按基本数据类型写入和读取,所以在读取的时候一定严格按照写入的顺序。
2、第9行的位置上,由于在写入的时候,导致访问的指针的位置在文件的结尾处,现在读取的时候,需要将访问指针的位置重置到文件开头处。
(3)、追加内容
public static void main(String[] args) throws IOException
{
RandomAccessFile raf = new RandomAccessFile("D:/out.txt","rw");
raf.seek(raf.length());
raf.write("\r\n中国移动阅读基地".getBytes());
}
执行结果:

1、这段程序演示了在文件原有内容的基础上去追加内容。其中seek方法就是将访问指针移动到文件内容的末尾。
2、RandomAccessFile依然只能追加,不能像文件的指定位置插入内容。如果强制将文件记录指针移动到中间位置后开始输出内容,则新的内容会覆盖文件中原有的内容。
3、如果需要向文件指定的位置插入内容,程序需要先把插入点后面的内容读入缓冲区,等插入完成后,再讲缓冲区的内容追加到文件的后面。
(4)、指定位置插入
public static void main(String[] args)
{
try
{
insert("d:/out.txt",5,"插入的内容");
}
catch (IOException e)
{
e.printStackTrace();
}
} private static void insert(String fileName,long pos,String content) throws IOException
{
//创建临时空文件
File tempFile = File.createTempFile("temp",null);
//在虚拟机终止时,请求删除此抽象路径名表示的文件或目录
tempFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempFile); RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
raf.seek(pos);
byte[] buffer = new byte[4];
int num = 0;
while(-1 != (num = raf.read(buffer)))
{
fos.write(buffer,0,num);
}
raf.seek(pos);
raf.write(content.getBytes());
FileInputStream fis = new FileInputStream(tempFile);
while(-1 != (num = fis.read(buffer)))
{
raf.write(buffer,0,num);
}
}
执行结果:

1、这里插入内容的原理就是:先把插入点后面的内容读入缓冲区,等插入完成后,再讲缓冲区的内容追加到文件的后面。
深入理解JAVA I/O系列四:RandomAccessFile的更多相关文章
- 深入理解java内存模型系列文章
转载关于java内存模型的系列文章,写的非常好. 深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模 ...
- java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现
java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...
- 《深入理解Java虚拟机》(四)虚拟机性能监控与故障处理工具
虚拟机性能监控与故障处理工具 详解 4.1 概述 本文参考的是周志明的 <深入理解Java虚拟机> 第四章 ,为了整理思路,简单记录一下,方便后期查阅. JDK本身提供了很多方便的JVM性 ...
- 深入理解JAVA I/O系列一:File
I/O简介 I/O问题可以说是当今web应用中所面临的的主要问题之一,大部分的web应用系统的瓶颈都是I/O瓶颈.这个系列主要介绍JAVA的I/O类库基本架构.磁盘I/O工作机制.网络I/O工作机制以 ...
- Java新知识系列 四
[]URL的组成<协议>://<主机>:<端口>/<路径> . []线程的定义实例化和启动. []类的final变量初始化需要满足的条件. []管道通信 ...
- 深入理解JAVA I/O系列二:字节流详解
流的概念 JAVA程序通过流来完成输入/输出.流是生产或消费信息的抽象,流通过JAVA的输入输出与物理设备链接,尽管与它们链接的物理设备不尽相同,所有流的行为具有相同的方式.这样就意味一个输入流能够抽 ...
- 深入理解JAVA I/O系列六:Linux中的IO模型
IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大致描述了数据从外部磁盘向运行中程序的内存中移动的过程. 用户空间.内核空间 现在操作系统都是采用虚拟存储器, ...
- 深入理解Java内存模型(四)——volatile
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...
- 【转】深入理解Java内存模型(四)——volatile
volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特别.理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这 ...
随机推荐
- Direct3D中 SetStreamSource 函数与数据流
Microsoft? DirectX? 8.0引入了数据流的概念,用来把数据绑定到着色器使用的输入寄存器.一个数据流是一个成员数据的数组,每个成员由一个或多个元素构成,这些元素代表单个实体,如位置.法 ...
- CF13E Holes LCT
CF13E Holes LG传送门 双倍经验题,几乎同[HNOI2010]弹飞绵羊,LCT练手题,LG没有LCT题解于是发一波. 从当前点向目标点连边,构成一棵树,带修改就用LCT动态维护答案,由于不 ...
- CF1039D You Are Given a Tree 根号分治,贪心
CF1039D You Are Given a Tree LG传送门 根号分治好题. 这题可以整体二分,但我太菜了,不会. 根号分治怎么考虑呢?先想想\(n^2\)暴力吧.对于每一个要求的\(k\), ...
- Java类的加载的一个小问题
前言 之前写了一篇文章专门介绍了一下类的加载和对象的创建流程,然后收到了一个博友的疑问,觉得蛮好的,在这里和大家分享下. 博文地址:[Java基础]Java类的加载和对象创建流程的分析 疑问 类在加载 ...
- 数据结构与算法 —— 链表linked list(06)
回文链表 链接 请检查一个链表是否为回文链表. 进阶:你能在 O(n) 的时间和 O(1) 的额外空间中做到吗? 解题思路: 回文链表的特点就是对称. 把链表放到栈中去,利用栈的先进后出的规则,和原链 ...
- python中函数的定义和详细的使用方法
1. 函数的概念,函数是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 2. 函数的作用,使用函数可以加强代码的复用性,提高程序编写的效率 3. 函数的使用,函数必须先创建才 ...
- ROC曲线与AUC
一.ROC曲线 1.简介 ROC曲线全称是"受试者工作特征曲线 "(Receiver Operating Characteristic curve),又称为感受性曲线(Sensit ...
- implode函数的升级版,将一个多维数组的值转化为字符串
/** * implode函数的升级版 * 将一个多维数组的值转化为字符串 * @param $glue * @param $data * @return string */function mult ...
- 【Unity Shader】(十) ------ UV动画原理及简易实现
笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...
- Laya 1.x 按文件夹TS代码合并
Laya 1.x 使用TS开发时,经常会碰到代码文件太多,加载index.html时时间太长的问题.Laya编辑器貌似没有自带JS代码合并的功能.基于Laya去实现JS合并需要修改编辑器源码,合并JS ...