23 Java学习之RandomAccessFile
Posted Hermioner
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23 Java学习之RandomAccessFile相关的知识,希望对你有一定的参考价值。
一. 源码结构
我们可以看到它的父类是Object,没有继承字节流、字符流家族中任何一个类。并且它实现了DataInput、DataOutput这两个接口,也就意味着这个类既可以读也可以写。RandomAccessFile 是随机访问文件(包括读/写)的类。它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据。
需要注意的是,RandomAccessFile 虽然属于java.io包,但它不是InputStream或者OutputStream的子类;它也不同于FileInputStream和FileOutputStream。 FileInputStream 只能对文件进行读操作,而FileOutputStream 只能对文件进行写操作;但是,RandomAccessFile 同时支持文件的读和写,并且它支持随机访问。
随机流不是IO流。
二. 存在意义
1、是JAVA I/O流体系中功能最丰富的文件内容访问类,它提供了众多方法来访问文件内容。
2、由于可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,RandomAccessFile将是更好的选择。
3、可以用来访问保存数据记录的文件,文件的记录的大小不必相同,但是其大小和位置必须是可知的。
这个类在很多资料上翻译成中文都是:随机访问文件,在中文里,随机是具有不确定的含义,指一会访问这里,一会访问那里的意思。如果以这种语义来解释的话,就会感到很困惑。其实,Random在英文中不仅仅有随机,还有任意的意思。如果中文名为任意访问文件是不是就会更好的理解。任意表示我们可以指定文件中任何一个位置去操作一个文件。
4.实际项目举例:
比如接到一个任务向一个已经有2G数据得txt文本里面末尾追加一行字,比如“我爱我家”。我们可能会直接将2G文件中得内容读取出来,然后转换成字符串,再用连接符将要新添加得这一行加上。可以,如果当这个数据文件变得越来越大,比如达到8G,可以我们得开发剩余内存只有5G。倘若我们还是采取老办法,强制读取数据并追加,则会产生内存溢出得异常现象。因此,就有了RandomAccessFile得产生。它可以进行任意访问,程序可以直接跳到任意地方来读写数据。我们不再需要将文件从头读到尾,只需要指定位置访问数据就行。
三. RandomAccessFile模式说明
RandomAccessFile共有4种模式:"r", "rw", "rws"和"rwd"。
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。 "rw" 打开以便读取和写入。 "rws" 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。 "rwd" 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
说明:
1. 什么是“元数据”,即metadata?
英文解释如下:
The definition of metadata is "data about other data." With a file system, the data is contained in its files and directories, and the metadata tracks information about each of these objects: Is it a regular file, a directory, or a link? What is its size, creation date, last modified date, file owner, group owner, and access permissions?
大致意思是:
metadata是“关于数据的数据”。在文件系统中,数据被包含在文件和文件夹中;metadata信息包括:“数据是一个文件,一个目录还是一个链接”,“数据的创建时间(简称ctime)”,“最后一次修改时间(简称mtime)”,“数据拥有者”,“数据拥有群组”,“访问权限”等等。
2. "rw", "rws", "rwd" 的区别。
当操作的文件是存储在本地的基础存储设备上时(如硬盘, NandFlash等),"rws" 或 "rwd", "rw" 才有区别。
当模式是 "rws" 并且 操作的是基础存储设备上的文件;那么,每次“更改文件内容[如write()写入数据]” 或 “修改文件元数据(如文件的mtime)”时,都会将这些改变同步到基础存储设备上。
当模式是 "rwd" 并且 操作的是基础存储设备上的文件;那么,每次“更改文件内容[如write()写入数据]”时,都会将这些改变同步到基础存储设备上。
当模式是 "rw" 并且 操作的是基础存储设备上的文件;那么,关闭文件时,会将“文件内容的修改”同步到基础存储设备上。至于,“更改文件内容”时,是否会立即同步,取决于系统底层实现。
四. RandomAccessFile使用方法
下面来看下RandomAccessFile类中比较重要的2个方法,其他的和普通IO类似,在这里,就不详细说明了。
方法名 | 作用 |
getFilePointer() | 返回文件记录指针的当前位置 |
seek(long pos) | 将文件记录指针定位到pos的位置 |
1 package com.test.a; 2 3 import java.io.IOException; 4 import java.io.RandomAccessFile; 5 6 public class Test { 7 public static void main(String args[]) throws IOException{ 8 RandomAccessFile accessFile=new RandomAccessFile("C:\\\\Users\\\\hermioner\\\\Desktop\\\\test.txt", "r"); 9 System.out.println("RandomAccessFeile文件指针的初始位置:"+accessFile.getFilePointer());//1. 10 accessFile.seek(10); 11 System.out.println("RandomAccessFeile文件指针的初始位置:"+accessFile.getFilePointer()); 12 byte buffer[]=new byte[40]; 13 int hasRead=0; 14 while((hasRead=accessFile.read(buffer))>0) { 15 System.out.println(hasRead); 16 System.out.println("RandomAccessFeile文件指针的初始位置:"+accessFile.getFilePointer()); 17 System.out.println(new String(buffer,0,hasRead)); 18 } 19 20 } 21 } 22 /** 23 * 1.第一处返回文件记录指针为0,即文本得最开始处。 24 * 2.当执行了seek(10)以后,就跳了10个字符,这是得文件记录指针应该在10 25 * 3.开始任意位置读取数据,一次读取hasRead个,最多读取40个。 26 * 4.第一次读取了40个,即此时得指针应该移动到了40+10=50处 27 * 5.第二次开始读取,只读取了34个(其中包含了一个换行符,因此实际上跳动了34个位置,即已经读取完了,此时应该在84位置处)。 28 */ 29 30 //RandomAccessFeile文件指针的初始位置:0 31 //RandomAccessFeile文件指针的初始位置:10 32 //40 33 //RandomAccessFeile文件指针的初始位置:50 34 //life,I love my family. 35 //I want to become 36 //34 37 //RandomAccessFeile文件指针的初始位置:84 38 // a professional software engineer.
note: test.txt文档中的内容如下:
2. seek
1 package com.test.a; 2 3 import java.io.IOException; 4 import java.io.RandomAccessFile; 5 6 public class Test { 7 public static void main(String args[]) throws IOException{ 8 //以读写的方式创建了一个对象 9 RandomAccessFile accessFile=new RandomAccessFile("C:\\\\Users\\\\hermioner\\\\Desktop\\\\test.txt", "rw"); 10 accessFile.seek(2); 11 System.out.println(accessFile.getFilePointer()); 12 accessFile.seek(2); 13 System.out.println(accessFile.getFilePointer()); 14 } 15 }
说明:seek(number)可以用来每次定位到什么地方。当读取文件的时候,如果不去调用这个方法,getFilePointer的时候,会随着读取的位置变动而变动;倘若调用了seek,每次即使读取了数据位置有变动,一旦调用seek,就会回到seek指定的这个number处来,即getFilePointer等于这个Number.
3. 追加数据
1 package com.test.a; 2 3 import java.io.IOException; 4 import java.io.RandomAccessFile; 5 6 public class Test { 7 public static void main(String args[]) throws IOException{ 8 //以读写的方式创建了一个对象 9 RandomAccessFile accessFile=new RandomAccessFile("C:\\\\Users\\\\hermioner\\\\Desktop\\\\test.txt", "rw"); 10 //将记录指针移动到文件的最后进行追加 11 accessFile.seek(accessFile.length()); 12 accessFile.write("I can success".getBytes()); 13 } 14 } 15 16 17 I love my life,I love my family. 18 I want to become a professional software engineer.I can success
4. 任意位置插入数据
1 /** 2 * 实现向指定位置 3 * 插入数据 4 * @param fileName 文件名 5 * @param points 指针位置 6 * @param insertContent 插入内容 7 * **/ 8 public static void insert(String fileName,long points,String insertContent){ 9 try{ 10 File tmp=File.createTempFile("tmp", null); 11 tmp.deleteOnExit();//在JVM退出时删除 12 13 RandomAccessFile raf=new RandomAccessFile(fileName, "rw"); 14 //创建一个临时文件夹来保存插入点后的数据 15 FileOutputStream tmpOut=new FileOutputStream(tmp); 16 FileInputStream tmpIn=new FileInputStream(tmp); 17 raf.seek(points); 18 /**将插入点后的内容读入临时文件夹**/ 19 20 byte [] buff=new byte[1024]; 21 //用于保存临时读取的字节数 22 int hasRead=0; 23 //循环读取插入点后的内容 24 while((hasRead=raf.read(buff))>0){ 25 // 将读取的数据写入临时文件中 26 tmpOut.write(buff, 0, hasRead); 27 } 28 29 //插入需要指定添加的数据 30 raf.seek(points);//返回原来的插入处 31 //追加需要追加的内容 32 raf.write(insertContent.getBytes()); 33 //最后追加临时文件中的内容 34 while((hasRead=tmpIn.read(buff))>0){ 35 raf.write(buff,0,hasRead); 36 } 37 }catch(Exception e){ 38 e.printStackTrace(); 39 } 40 }
说明:这里插入内容的原理就是:先把插入点后面的内容读入缓冲区,等插入完成后,再讲缓冲区(通过tempout写到了buffer中)的内容追加到文件的后面。
note:RandomAccessFile本身是没有这个任意位置插入数据的方法的。
文献参考:
https://www.cnblogs.com/zuochengsi-9/p/6485737.html
https://www.cnblogs.com/skywang12345/p/io_26.html
https://www.cnblogs.com/dongguacai/p/5699444.html
以上是关于23 Java学习之RandomAccessFile的主要内容,如果未能解决你的问题,请参考以下文章