Java IO体系之RandomAccessFile浅析

一、RandomAccessFile综述:

1.1RandomAccessFile简介

  • RandomAccessFile是java Io体系中功能最丰富的文件内容访问类。即可以读取文件内容,也可以向文件中写入内容。

  • RandomAccessFile的唯一父类是Object,与其他流父类不同。是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。

  • 由于RandomAccessFile可以自由访问文件的任意位置,所以如果我们希望只访问文件的部分内容,RandomAccessFile将是更好的选择。

  • 与OutputStearm,Writer等输出流不同的是,RandomAccessFile类允许自由定位文件记录指针,程序可以直接跳到文件的任意位置来读写数据,所以RandomAccessFile可以不从文件开始的地方进行输出,如果需要向已存在的文件后追加内容。则可以使用RandomAccessFile。

  • 这个类在很多资料上翻译成中文都是:随机访问文件,在中文里,随机是具有不确定的含义,指一会访问这里,一会访问那里的意思。如果以这种语义来解释的话,就会感到很困惑。其实,Random在英文中不仅仅有随机,还有任意的意思。如果中文名为任意访问文件是不是就会更好的理解。任意表示我们可以指定文件中任何一个位置去操作一个文件。

1.2、RandomAccessFile数据结构

  这个是JDK上的截图,我们可以看到它的父类是Object,没有继承字节流、字符流家族中任何一个类。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口,意味着这个类即可以读也可以写),它和字节流、字符流类系毫不相干,甚至都没有用InputStream和OutputStream已经准备好的功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。

1.3.RandomAccessFile的整体介绍

  • RandomAccessFile类包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由的移动记录指针,即可以向前移动,也可以向后移动。RandomAccessFile包含了以下两个方法来操作文件的记录指针:RandomAccessFile即可以读文件,也可以写,所以它即包含了完全类似于InputStream的3个read()方法,其用法和InputStream的3个read()方法完全一样;也包含了完全类似于OutputStream的3个write()方法,其用法和OutputStream的3个Writer()方法完全一样。除此之外,RandomAccessFile还包含了一系类的readXXX()和writeXXX()方法来完成输入和输出。

    • long getFilePointer(); 返回文件记录指针的当前位置
    • void seek(long pos); 将文件记录指针定位到pos位置
  • RandomAccessFile有两个构造器,其实这两个构造器基本相同,只是指定文件的形式不同而已,一个使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFile对象还需要指定一个mode参数。该参数指定RandomAccessFile的访问模式,有以下4个值:

    • “r” 以只读方式来打开指定文件夹。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常。

    • “rw” 以读,写方式打开指定文件。如果该文件尚不存在,则试图创建该文件。

    • “rws” 以读,写方式打开指定文件。相对于”rw” 模式,还要求对文件内容或元数据的每个更新都同步写入到底层设备。

    • “rwd” 以读,写方式打开指定文件。相对于”rw” 模式,还要求对文件内容每个更新都同步写入到底层设备。

1.4工作方式

  • 基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream粘起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件,从这一点上看,假如RandomAccessFile继承了DataInputStream,它也许会干得更好。
  • 只有RandomAccessFile才有seek方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。
  • RandomAccessFile的绝大多数功能,如果不是全部的话,已经被JDK1.4的nio的"内存映射文件(memory-mapped files)"给取代了。

二、RandomAccessFile方法摘要:

构造方法摘要
RandomAccessFile(File file, String mode)
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
RandomAccessFile(String name, String mode)

          创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
方法摘要
 void close()

          关闭此随机访问文件流并释放与该流关联的所有系统资源。
 FileChannel getChannel()

          返回与此文件关联的唯一 FileChannel
对象。
 FileDescriptor getFD()

          返回与此流关联的不透明文件描述符对象。
 long getFilePointer()

          返回此文件中的当前偏移量。
 long length()

          返回此文件的长度。
 int read()

          从此文件中读取一个数据字节。
 int read(byte[] b)

          将最多 b.length 个数据字节从此文件读入 byte 数组。
 int read(byte[] b,
int off, int len)

          将最多 len 个数据字节从此文件读入 byte
数组。
 boolean readBoolean()

          从此文件读取一个 boolean
 byte readByte()

          从此文件读取一个有符号的八位值。
 char readChar()

          从此文件读取一个字符。
 double readDouble()

          从此文件读取一个 double
 float readFloat()

          从此文件读取一个 float
 void readFully(byte[] b)

          将 b.length 个字节从此文件读入 byte 数组,并从当前文件指针开始。
 void readFully(byte[] b,
int off, int len)

          将正好 len 个字节从此文件读入 byte
数组,并从当前文件指针开始。
 int readInt()

          从此文件读取一个有符号的 32 位整数。
 String readLine()

          从此文件读取文本的下一行。
 long readLong()

          从此文件读取一个有符号的 64 位整数。
 short readShort()

          从此文件读取一个有符号的 16 位数。
 int readUnsignedByte()

          从此文件读取一个无符号的八位数。
 int readUnsignedShort()

          从此文件读取一个无符号的 16 位数。
 String readUTF()

          从此文件读取一个字符串。
 void seek(long pos)

          设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
 void setLength(long newLength)

          设置此文件的长度。
 int skipBytes(int n)

          尝试跳过输入的 n 个字节以丢弃跳过的字节。
 void write(byte[] b)

          将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。
 void write(byte[] b,
int off, int len)

          将 len 个字节从指定 byte
数组写入到此文件,并从偏移量 off 处开始。
 void write(int b)

          向此文件写入指定的字节。
 void writeBoolean(boolean v)

          按单字节值将 boolean 写入该文件。
 void writeByte(int v)

          按单字节值将 byte 写入该文件。
 void writeBytes(String s)

          按字节序列将该字符串写入该文件。
 void writeChar(int v)

          按双字节值将 char 写入该文件,先写高字节。
 void writeChars(String s)

          按字符序列将一个字符串写入该文件。
 void writeDouble(double v)

          使用 Double 类中的 doubleToLongBits
方法将双精度参数转换为一个 long,然后按八字节数量将该 long
值写入该文件,先定高字节。
 void writeFloat(float v)

          使用 Float 类中的 floatToIntBits 方法将浮点参数转换为一个
int,然后按四字节数量将该 int 值写入该文件,先写高字节。
 void writeInt(int v)

          按四个字节将 int 写入该文件,先写高字节。
 void writeLong(long v)

          按八个字节将 long 写入该文件,先写高字节。
 void writeShort(int v)

          按两个字节将 short 写入该文件,先写高字节。
 void writeUTF(String str)

          使用 modified UTF-8
编码以与机器无关的方式将一个字符串写入该文件。

三、实例分析

 1 package me.io.raffile;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.RandomAccessFile;
6 import java.util.Arrays;
7
8 public class RafDemo {
9
10 public static void main(String[] args) throws IOException {
11 File demo = new File("demo");
12 if(!demo.exists())
13 demo.mkdir();
14 File file = new File(demo, "raf.dat");
15 if (!file.exists())
16 file.createNewFile();
17 RandomAccessFile raf = new RandomAccessFile(file, "rw");
18 //指针的位置
19 System.out.println(raf.getFilePointer());
20 raf.write('A');//只写了一个字节
21 System.out.println(raf.getFilePointer());
22
23 raf.write('B');
24 System.out.println(raf.getFilePointer());
25
26 //Java中最大的整数
27 int i = 0x7fffffff;
28
29 //占四个字节,如果要把i写进去,就得写四次
30 raf.write(i >>> 24);//高八位
31 raf.write(i >>> 16);
32 raf.write(i >>> 8);
33 raf.write(i);
34
35 //可以直接写一个int
36 raf.writeInt(i);
37
38 String string = "中";
39 byte[] bytes = string.getBytes();
40 raf.write(bytes);
41 System.out.println(raf.length());
42
43 //读文件,必须把指针移到头部
44 raf.seek(0);
45 //一次性读取,把文件中的内容都堵到字节数组
46 byte[] buf = new byte[(int) raf.length()];
47 raf.read(buf);
48 System.out.println(Arrays.toString(buf));
49 for (byte b : buf) {
50 System.out.print(Integer.toHexString(b & 0xff) + " ");
51 }
52 raf.close();
53 }
54 }

三、专题总结(FIle与RandomAccessFile)

注:这里File类的介绍可参见我的上一篇博文

java.io.File类用于表示文件(目录)
File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问

RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置

(1)java文件模型
  在硬盘上的文件是byte byte byte存储的,是数据的集合
(2)打开文件
  有两种模式"rw"(读写)  "r"(只读)
  RandomAccessFile raf = new RandomeAccessFile(file,"rw")
  文件指针,打开文件时指针在开头 pointer = 0;
(3) 写方法
    raf.write(int)--->只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
(4)读方法
   int b = raf.read()--->读一个字节

(5)文件读写完成以后一定要关闭(Oracle官方说明)

参考文章:

  http://blog.csdn.net/nightcurtis/article/details/51384126

  https://www.cnblogs.com/dongguacai/p/5699444.html

Java IO体系之RandomAccessFile浅析的更多相关文章

  1. Java IO体系之File类浅析

    Java IO体系之File类浅析 一.File类介绍 位于java.io下的Java File类以抽象的方式代表文件名和目录路径名.该类主要用于文件和目录的创建.文件的查找和文件的删除等.File对 ...

  2. JAVA基础知识之IO——Java IO体系及常用类

    Java IO体系 个人觉得可以用"字节流操作类和字符流操作类组成了Java IO体系"来高度概括Java IO体系. 借用几张网络图片来说明(图片来自 http://blog.c ...

  3. Java IO体系综述

    Java IO体系综述 一.流的概念 在Java API中,可以从其中读入一个字节序列的对象称作输入流,而可以向其中写入一个字节序列的对象称作输出流.这些字节序列的来源地和目的地可以是文件,而且通常都 ...

  4. 高效IO之Java IO体系(一)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 个人觉得可以用“字节流操作类和字符流操作类组成了Java IO体系”来高度概括J ...

  5. 【Java IO流】RandomAccessFile类的使用

    RandomAccessFile类的使用 RandomAccessFile类是java提供的对文件内容的访问,既可以读文件,也可以写文件. 支持随机访问文件,可以访问文件的任意位置. RandomAc ...

  6. JAVA IO 体系

    一.体系结构

  7. Java IO的RandomAccessFile的使用(转)

    现有如下的一个需求,向已存在1G数据的txt文本里末尾追加一行文字,内容如下“Lucene是一款非常优秀的全文检索库”.可能大多数朋友会觉得这个需求很easy,说实话,确实easy,然后XXX君开始实 ...

  8. 关于Java IO与NIO知识都在这里

    由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读.每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾. Java面试通关手册(Java学习 ...

  9. Java 基础之详解 Java IO

    Java IO基本概念 Java IO:即Java输入/输出系统,区分Java的输入和输出:把自己当成程序, 当你从外边读数据到自己这里就用输入(InputStream/Reader), 向外边写数据 ...

随机推荐

  1. 0004. 寻找两个有序数组的中位数(Java)

    4. 寻找两个有序数组的中位数 https://leetcode-cn.com/problems/median-of-two-sorted-arrays/ 最简单的就是用最简单的,把两个数组分别抽出然 ...

  2. LinkedHashMap的特殊之处

    一.前言 乍眼一看会怀疑或者问LinkedHashMap与HashMap有什么区别? 它有什么与众不同之处?  由于前面已经有两篇文章分析了HashMap,今天就看看LinkedHashMap.(基于 ...

  3. 【Android】Field requires API level 4 (current min is 1): android.os.Build.VERSION#SDK_INT

    刚遇到了这个问题: Field requires API level 4 (current min is 1): android.os.Build.VERSION#SDK_INT 解决方法: 修改 A ...

  4. Linux系统下增加LV(逻辑卷)容量 、Linux系统下减少LV(逻辑卷)容量

    查看文件系统现有lv_test容量,总计4.9G,已使用3% 命令 df -h   查看现有磁盘情况,我们发现磁盘sdb共有1305个柱面,每个柱面大小是8225280 bytes (大约8M).有一 ...

  5. JAVA并发编程之倒计数器CountDownLatch

    CountDownLatch 的使用场景:在主线程中开启多线程去并行执行任务,并且主线程需要等待所有子线程执行完毕后汇总返回结果. 我把源码中的英文注释全部删除,写上自己的注释.就剩下 70 行不到的 ...

  6. 基于vue2.0搭建项目流程

    搭建vue2.0项目--myproject 一. 环境搭建: 1 打开命令行(cmd) 2 安装node node官网 3 安装 vue-cli步骤如下: npm install -g vue-cli ...

  7. 邮件服务配置(虚拟域&虚拟用户)

    邮件服务配置(虚拟域&虚拟用户) 现在我做的是: Linux + httpd + php + mariadb + postfix + dovecot + phpMyAdmin + postfi ...

  8. 以太坊RLPx传输协议

    本文主要内容翻译自:The RLPx Transport Protocol,其中添加了一些个人的理解,由于密码学水平有限,不正确之处望指正.另外原文可能已经更新,最新内容请直接阅读原文. 本文档定义了 ...

  9. Unity经典游戏教程之:贪吃蛇

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  10. JDK1.8源码分析03之idea搭建源码阅读环境

    序言:上一节说了阅读源码的顺序,有了一个大体的方向,咱们就知道该如何下手.接下来,就要搭建一个方便阅读源码及debug的环境.有助于跟踪源码的调用情况. 目前新开发的项目, 大多数都是基于JDK1.8 ...