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. Linux mysql开启远程访问

    默认情况下远程访问会出现 Can't connect to MySQL server on '192.168.10.18′ (10061) 错误是因为,mysql的默认配置为了增强安全性,禁止了非本机 ...

  2. 转 - RPC调用和HTTP调用的区别

    很长时间以来都没有怎么好好搞清楚RPC(即Remote Procedure Call,远程过程调用)和HTTP调用的区别,不都是写一个服务然后在客户端调用么?这里请允许我迷之一笑~Naive!本文简单 ...

  3. python网络爬虫(14)使用Scrapy搭建爬虫框架

    目的意义 爬虫框架也许能简化工作量,提高效率等.scrapy是一款方便好用,拓展方便的框架. 本文将使用scrapy框架,示例爬取自己博客中的文章内容. 说明 学习和模仿来源:https://book ...

  4. JavaOOP 对象和封装

    1.后缀:jsp---相当于html,但是它里面可以写java代码. 2.包名取名规则 a.网站域名倒着写 b.字母小写 3.类名取名规则 a.首字母大写 4.三目运算(适用简单的if-else) 条 ...

  5. GitLab与Git的结合

    作为一名刚入职的大数据初级开发工程师,来到公司后发现代码是部署在GItLab上,之前一直认为代码可以放在码云.github上面,然后就很迷惑就对GitLab进行了了解,将git 和gitlab结合起来 ...

  6. 使用Redis为注册中心的Dubbo微服务架构(基于SpringBoot)

    title: 使用Redis为注册中心的Dubbo微服务架构(基于SpringBoot) date: 2019-07-30 14:06:29 categories: 架构 author: mrzhou ...

  7. Android开发进阶——自定义View的使用及其原理探索

    在Android开发中,系统提供给我们的UI控件是有限的,当我们需要使用一些特殊的控件的时候,只靠系统提供的控件,可能无法达到我们想要的效果,这时,就需要我们自定义一些控件,来完成我们想要的效果了.下 ...

  8. 使用ForkJoinPool来多线程的拆分任务,执行任务,合并结果。

    ForkJoinPool 是jdk1.7 由Doug Lea 写的实现   递归调用任务拆分,合并,的线程池. 代码示例: package www.itbac.com; import com.alib ...

  9. 五、Python基础(2)

    五,Python基础(2) 1.数据类型基础 (一)什么是数据类型? 用于区分变量值的不同类型. (二)为何对数据分类? 针对不同状态就应该用不同类型的数据去标识. (三)数据类型分类 1.数字类型 ...

  10. Selenium+java - 借助autolt完成上传文件操作

    写在前面: 上传文件是每个自动化测试同学会遇到,而且可以说是面试必考的问题,标准控件我们一般用sendkeys()就能完成上传,但是我们的测试网站的上传控件一般为自己封装的,用传统的上传已经不好用了, ...