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. 《 C#语言学习笔记》——自动属性

    属性是访问对象状态的首选方式,因为它们禁止外部代码实现对象内部的数据存储机制.属性还对内部数据的访问方式有了更多控制.一般以非常标准的方式定义属性,即通过一个公共属性直接访问一个私有成员. 利用自动属 ...

  2. Java EE产生的背景

    为了满足开发多层体系结构的企业级应用的需求,Java公司的创始人Sun公司在早期的J2SE(Java 2 Platform Standard Edition)基础上,针对企业级应用的各种需求,提出了J ...

  3. JNDI总结(一)

    一.数据源的由来 在Java开发中,使用JDBC操作数据库的四个步骤如下:   ①加载数据库驱动程序(Class.forName("数据库驱动类");)   ②连接数据库(Conn ...

  4. html5教程 《实用技巧》—让你的网站变成响应式的3个简单步骤

    如今,一个网站只在桌面屏幕上好看是远远不够的,同时也要在平板电脑和智能手机中能够良好呈现.响应式的网站是指它能够适应客户端的屏幕尺寸,自动响应客户端尺寸变化.在这篇文章中,我将向您展示如何通过3个简单 ...

  5. 【Python-Django】浏览器同源策略

    1995年,同源政策由 Netscape 公司引入浏览器.目前,所有浏览器都实行这个政策. 同源策略是浏览器的一个安全功能,不同源的客户端脚本(js文件)在没有明确授权的情况下,不能读写对方资源.只有 ...

  6. 【有容云】PPT | 容器落地之二三事儿

    编者注: 本文为10月29日有容云联合创始人兼研发副总裁江松在 Docker Live时代线下系列-广州站中演讲的PPT,本次线下沙龙为有容云倾力打造Docker Live时代系列主题线下沙龙,每月一 ...

  7. Codeforces 468C Hack it!

    https://www.luogu.org/problemnew/show/CF468C http://codeforces.com/contest/468/problem/C #include &l ...

  8. 直方图均衡基本原理及Python实现

    1. 基本原理 通过一个变换,将输入图像的灰度级转换为`均匀分布`,变换后的灰度级的概率密度函数为 $$P_s(s) = \frac{1}{L-1}$$ 直方图均衡的变换为 $$s = T(r) = ...

  9. 让techempower帮你通讯服务框架的性能

    在编写服务应用框架的时候一般都需要进行性能测试,但自己测试毕竟资源受限所以很难做更高性能上的测试.其实GitHub上有一个项目可以让开发人员提交自己的框架服务代码然后进行一个标准测试:现在已经有上百个 ...

  10. linux环境下搭建自动化Jenkins管理工具

    一.搭建一个jak--tomcat服务器到自己的linux服务器上 具体的服务器搭建这里可以参考华华大佬的博客:https://www.cnblogs.com/liulinghua90/p/46614 ...