【Java NIO的深入研究2】RandomAccessFile的使用
RandomAccessFile
RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。
RandomAccessFile不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至不使用InputStream和OutputStream类中已经存在的任何功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。
基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream结合起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件。
只有RandomAccessFile才有seek搜寻方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。
RandomAccessFile的绝大多数功能,但不是全部,已经被JDK 1.4的nio的"内存映射文件(memory-mapped files)"给取代了,你该考虑一下是不是用"内存映射文件"来代替RandomAccessFile了。
现有如下的一个需求,向已存在1G数据的txt文本里末尾追加一行文字,内容如下“Lucene是一款非常优秀的全文检索库”。可能大多数朋友会觉得这个需求很easy,说实话,确实easy,然后XXX君开始实现了,直接使用Java中的流读取了txt文本里原来所有的数据转成字符串后,然后拼接了“Lucene是一款非常优秀的全文检索库”,又写回文本里了,至此,大功告成。后来需求改了,向5G数据的txt文本里追加了,结果XXX君傻了,他内存只有4G,如果强制读取所有的数据并追加,会报内存溢出的异常。
其实上面的需求很简单,如果我们使用JAVA IO体系中的RandomAccessFile类来完成的话,可以实现零内存追加。其实这就是支持任意位置读写类的强大之处。
RandomAccessFile是Java中输入,输出流体系中功能最丰富的文件内容访问类,它提供很多方法来操作文件,包括读写支持,与普通的IO流相比,它最大的特别之处就是支持任意访问的方式,程序可以直接跳到任意地方来读写数据。
如果我们只希望访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将会带来更简洁的代码以及更好的性能。
下面来看下RandomAccessFile类中比较重要的2个方法,其他的和普通IO类似,在这里,就不详细说明了。
方法名 作用
getFilePointer() 返回文件记录指针的当前位置
seek(long pos) 将文件记录指针定位到pos的位置
1.功能one,读取任意位置的数据
2.功能two,追加数据
3.功能three,任意位置插入数据
public class Random {
public static void main(String[] args) {
String path="randomtest.txt";
int seekPointer=20;
randomRed(path,seekPointer);//读取的方法
randomWrite(path);//追加写的方法
//insert(path, 23, "\nlucene是一个优秀的全文检索库");
}
public static void randomRed(String path,int pointe){
try{
RandomAccessFile raf=new RandomAccessFile(path, "r");
//获取RandomAccessFile对象文件指针的位置,初始位置是0
System.out.println("RandomAccessFile文件指针的初始位置:"+raf.getFilePointer());
raf.seek(pointe);//移动文件指针位置
byte[] buff=new byte[1024];
//用于保存实际读取的字节数
int hasRead=0;
//循环读取
while((hasRead=raf.read(buff))>0){
//打印读取的内容,并将字节转为字符串输入
System.out.println(new String(buff,0,hasRead));
}
}catch(Exception e){
e.printStackTrace();
}
}
public static void randomWrite(String path){
try{
/**以读写的方式建立一个RandomAccessFile对象**/
RandomAccessFile raf=new RandomAccessFile(path, "rw");
//将记录指针移动到文件最后
raf.seek(raf.length());
raf.write("我是追加的 \r\n".getBytes());
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 实现向指定位置
* 插入数据
* @param fileName 文件名
* @param points 指针位置
* @param insertContent 插入内容
* **/
public static void insert(String fileName,long points,String insertContent){
try{
File tmp=File.createTempFile("tmp", null);
tmp.deleteOnExit();//在JVM退出时删除
RandomAccessFile raf=new RandomAccessFile(fileName, "rw");
//创建一个临时文件夹来保存插入点后的数据
FileOutputStream tmpOut=new FileOutputStream(tmp);
FileInputStream tmpIn=new FileInputStream(tmp);
raf.seek(points);
/**将插入点后的内容读入临时文件夹**/
byte [] buff=new byte[1024];
//用于保存临时读取的字节数
int hasRead=0;
//循环读取插入点后的内容
while((hasRead=raf.read(buff))>0){
// 将读取的数据写入临时文件中
tmpOut.write(buff, 0, hasRead);
}
//插入需要指定添加的数据
raf.seek(points);//返回原来的插入处
//追加需要追加的内容
raf.write(insertContent.getBytes());
//最后追加临时文件中的内容
while((hasRead=tmpIn.read(buff))>0){
raf.write(buff,0,hasRead);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果:
最初randomtest.txt是这样的:

采用randomWrite(path);追加后txt文件是这样的:

采用insert(path, 23, "\nlucene是一个优秀的全文检索库"); txt文件是这样的:

【Java NIO的深入研究2】RandomAccessFile的使用的更多相关文章
- 【Java NIO的深入研究】 ServerSocketChannel
Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样.ServerSocketChannel类在 jav ...
- 【Java NIO的深入研究6】JAVA NIO之Scatter/Gather
Java NIO开始支持scatter/gather,scatter/gather用于描述从Channel(译者注:Channel在中文经常翻译为通道)中读取或者写入到Channel的操作. 分散(s ...
- 【Java NIO的深入研究1】缓冲区
缓冲区 传统的流和通道的对比 流 通道 慢 快 处理简单 处理复杂 单字节的传输 一块数据的传输 - Java.io.*已经重新写过 - 是对流的模拟 单向的 双向的 可直接访问 必须通过Buffer ...
- 【Java NIO的深入研究5】字符集Charset
Java 语言被定义为基于Unicode.一个字符实体由二个字节表示(如果是用UCS-2).但众多文件和数据流都是基于其它字符编码并以byte传输,操作文件内容就成了一个问题. 操作一个文件首先要对文 ...
- 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射
内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...
- 【Java NIO深入研究3】文件锁
1.1概述——文件锁 文件锁定初看起来可能让人迷惑.它 似乎 指的是防止程序或者用户访问特定文件.事实上,文件锁就像常规的 Java 对象锁 — 它们是 劝告式的(advisory) 锁.它们不阻止任 ...
- Java NIO ByteBuffer 的使用与源码研究
一.结论 ByteBuffer 是Java NIO体系中的基础类,所有与Channel进行数据交互操作的都是以ByteBuffer作为数据的载体(即缓冲区).ByteBuffer的底层是byte数组, ...
- java nio使用方法(转)
最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下 ...
- JAVA NIO学习二:通道(Channel)与缓冲区(Buffer)
今天是2018年的第三天,真是时光飞逝,2017年的学习计划还没有学习完成,因此继续开始研究学习,那么上一节我们了解了NIO,那么这一节我们进一步来学习NIO相关的知识.那就是通道和缓冲区.Java ...
随机推荐
- 常见的web负载均衡方法总结
Web负载均衡的方法有很多,下面介绍几种常见的负载均衡方法. 1.用户手动选择方法 这是一种较为古老的方式.通过在主站首页入口提供不同线路.不同服务器连接的方式,来实现负载均衡.这种方式在一些提供下载 ...
- html input select等控件宽度对不齐?请使用box-sizing。
今天终于明白为什么表单元素的宽度经常对不齐了,原来是计算的问题. 为元素设置:box-sizing: border-box;,则表明width的宽度为内容本身宽度+padding+border(高度一 ...
- 批处理学习笔记14 - 把所有.mp4文件全部拷贝进统一目录
今天下载了一套视频教程,结果发现不在同一个目录下,很乱.都放在不同文件夹下. 于是写了一个批处理来解决这个问题 @echo off for /r %%i in (*mp4) do ( copy %%i ...
- SourceInsight-查看java中接口对应的实现类
1.双击选中需要查看的接口名称,然后右击选择“Show in Relation Window” 2.然后在右侧会弹出一个Relation的窗口 如果没有列出对应的实现类,可以在接口名上再次右击,依次选 ...
- angular学习笔记(十九)-指令修改dom
本篇主要介绍angular使用指令修改DOM: 使用angular指令可以自己扩展html语法,还可以做很多自定义的事情.在后面会专门讲解这一块的知识,这一篇只是起到了解入门的作用. 与控制器,过滤器 ...
- bazel-链接第三方动态库,静态库。
demo4示例 链接第三方动态库,静态库. 使用cc_import链接外部库.原理是通过cc_import规则导入第三方库,然后cc_binary再依赖cc_import规则的target,也即依赖第 ...
- 李洪强iOS之集成极光推送一iOS SDK概述
李洪强iOS之集成极光推送一iOS SDK概述 JPush iOS 从上图可以看出,JPush iOS Push 包括 2 个部分,APNs 推送(代理),与 JPush 应用内消息. 红色部分是 A ...
- Freemarker-2.3.22 Demo - No02_绑定单个参数
package No02_绑定单个参数; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStre ...
- tortisegit 创建分支和合并分支
第一步:创建本地分支 点击右键选择TortoiseGit,选择Create Branch…,在Branch框中填写新分支的名称(若选中”switch to new branch”则直接转到新分支上,省 ...
- GNU风格 ARM汇编语法4
.GNU汇编语言定义入口点 汇编程序的缺省入口是_start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点. 例:定义入口点 .section .data < initializ ...