zoukankan      html  css  js  c++  java
  • 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. 读取任意位置的数据
     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.
    View Code

    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 }
    View Code

    说明: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
    View Code

    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     }  
    View Code

    说明:这里插入内容的原理就是:先把插入点后面的内容读入缓冲区,等插入完成后,再讲缓冲区(通过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

  • 相关阅读:
    计算机网络【七】:可靠传输的实现 (tcp窗口滑动以及拥塞控制)【转】
    计算机网络【六】:传输层-TCP概述 【转】
    计算机网络【五】:路由选择协议 【转】
    计算机网络【三】:数据链路层 【转】
    计算机网络【二】:物理层【转】
    计算机网络【一】:概述 【转】
    装饰模式-Decorator
    Java中的文件上传和下载
    模板方法模式-TemplateMethod
    策略模式-Strategy
  • 原文地址:https://www.cnblogs.com/Hermioner/p/9775023.html
Copyright © 2011-2022 走看看