Java_io体系之RandomAccessFile简介、走进源码及示例——20

RandomAccessFile

1、       类功能简介:

文件随机访问流、关心几个特点:

1、他实现的接口不再是InputStream、OutputStream中的任何一个、而是实现的DataInput、DataOutput。这也注定了他可以对java基础类型进行操作、而且是即可读取、也可以写入、关于这部分的方法大多数都是从DataInputStream、DataOutputStream那里荡来的。

2、如其名、随机流、这里的随机并不是不可控制、不可预测的去访问文件、而是可以通过指针的形式定位到具体的位置——“文件指针”、具体使用“文件指针”的方法:调用此流的seek(long n)方法来设置位置、使用此方法要注意的是如果传入的n大于文件长度、此方法不会改变文件长度、只是当写入下一个字节时会改变文件大小、即下一个写入的字节是添加在n后的。如果n小于文件长度、则会从n位置开始覆盖后面的file内容、

3、此流既可以读取文件、也可以写入文件、也可具有只读功能、但是没有只写功能、具体是哪种类型是在构造方法中指定的——String mode;具体的区别上面有说明。。

这里把实例放在了前面、因为源码和方法所占篇幅太长、有兴趣的可继续往下看。

2、       实例演示:

package com.chy.io.original.test;import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;public class RandomAccessFileTests {private static final File file = new File("D:\\rsf.txt");/*** 向文件中写入内容*/public static void testRandomAccessFileWriter() throws IOException{//要先将已有文件删除、避免干扰。if(file.exists()){file.delete();}RandomAccessFile rsfWriter = new RandomAccessFile(file, "rw");//不会改变文件大小、但是他会将下一个字符的写入位置标识为10000、也就是说此后只要写入内容、就是从10001开始存、rsfWriter.seek(10000);printFileLength(rsfWriter);      //result: 0//会改变文件大小、只是把文件的size改变、并没有改变下一个要写入的内容的位置、这里注释掉是为了验证上面的seek方法的说明内容//rsfWriter.setLength(10000);printFileLength(rsfWriter);        //result: 0//每个汉子占3个字节、写入字符串的时候会有一个记录写入字符串长度的两个字节rsfWriter.writeUTF("陈华应");   printFileLength(rsfWriter);     //result: 10011//每个字符占两个字节rsfWriter.writeChar('a');rsfWriter.writeChars("abcde");printFileLength(rsfWriter);        //result: 10023//再从“文件指针”为5000的地方插一个长度为100、内容全是'a'的字符数组//这里file长依然是10023、因为他是从“文件指针”为5000的地方覆盖后面的200个字节、下标并没有超过文件长度rsfWriter.seek(5000);char[] cbuf = new char[100];for(int i=0; i

3、 RandomAccessFile API简介:

A:构造方法

  RandomAccessFile(File file, String mode)     创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。 RandomAccessFile(String name, String mode)   从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。 
补充一:mode的取值有下面四种情况
"r"    以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw"   打开以便读取和写入。
"rws"  打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
"rwd"  打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
补充二:关于文件的“元数据”
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?
补充三:"rw"  "rws"  "rwd"之间的区别
当操作的文件是存储在本地的基础存储设备上时(如硬盘, NandFlash等),"rws" 或 "rwd", "rw" 才有区别。
当模式是 "rws" 并且 操作的是基础存储设备上的文件;那么,每次“更改文件内容[如write()写入数据]” 或 “修改文件元数据(如文件的mtime)”时,都会将这些改变同步到基础存储设备上。
当模式是 "rwd" 并且 操作的是基础存储设备上的文件;那么,每次“更改文件内容[如write()写入数据]”时,都会将这些改变同步到基础存储设备上。
当模式是 "rw" 并且 操作的是基础存储设备上的文件;那么,关闭文件时,会将“文件内容的修改”同步到基础存储设备上。至于,“更改文件内容”时,是否会立即同步,取决于系统底层实现。
一般使用前两个就ok。

B:一般方法

  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 编码以与机器无关的方式将一个字符串写入该文件。 

4、 源码分析

package com.chy.io.original.code;import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.nio.channels.FileChannel;import sun.nio.ch.FileChannelImpl;/*** 随机访问文件流、既可以对文件进行读取、也可以对文件进行写入、还可以写入java基础类型、不再是InputStream或者OutputStream的子类、* 而是实现了DataOutput、DataInput、通过这两个接口也可以看出、此类具有将java基础类型写入文件或者读取到程序中的功能、关于写入/读取文件基础类型* 的操作大多数都是剽窃DataInputStream/DataOutputStream的。*/public class RandomAccessFile implements DataOutput, DataInput, Closeable {java.io.RandomAccessFileprivate FileDescriptor fd;private FileChannel channel = null;private boolean rw;//标识此文件是否既可以读又可以写//标识不同mode对应的值private static final int O_RDONLY = 1;private static final int O_RDWR =   2;private static final int O_SYNC =   4;private static final int O_DSYNC =  8;/*** 使用指定的文件、模式构造RandomAccessFile、初始化参数、打开到文件的连接*/public RandomAccessFile(String name, String mode)throws FileNotFoundException{this(name != null ? new File(name) : null, mode);}/*** 使用指定的文件、模式构造RandomAccessFile、初始化参数、打开到文件的连接*/public RandomAccessFile(File file, String mode)throws FileNotFoundException{String name = (file != null ? file.getPath() : null);int imode = -1;if (mode.equals("r"))imode = O_RDONLY;else if (mode.startsWith("rw")) {imode = O_RDWR;rw = true;if (mode.length() > 2) {if (mode.equals("rws"))imode |= O_SYNC;else if (mode.equals("rwd"))imode |= O_DSYNC;elseimode = -1;}}if (imode  len) {newpos = len;}seek(newpos);/* return the actual number of bytes skipped */return (int) (newpos - pos);}// 'Write' primitives/*** 在当前“文件指针”标示的地方写入一个字节*/public native void write(int b) throws IOException;/*** 将b的一部分写入到文件中*/private native void writeBytes(byte b[], int off, int len) throws IOException;/*** 将b写入到文件中*/public void write(byte b[]) throws IOException {writeBytes(b, 0, b.length); }/*** 将b的一部分写入到文件中*/public void write(byte b[], int off, int len) throws IOException {writeBytes(b, off, len);}// 'Random access' stuff/*** 返回当前文件的偏移量、即“文件描述符”的位置*/public native long getFilePointer() throws IOException;/*** 设置“文件指针”的偏移量、从文件的开头开始计数、如果pos大于文件的长度、也不会改变文件的大小、* 文件的大小只有在当“文件指针”指向文件最后的时候、再向文件中写入字节才会扩展。*/public native void seek(long pos) throws IOException;/*** 返回文件的字节数*/public native long length() throws IOException;/*** 设置文件长度:*              if(newLength > originalLength)*                  扩展文件长度、新增加的长度使用默认值填充;*              else*                   截取源文件的前originalLength字节、如果源文件的偏移量大于newLength、则将源文件的偏移量设为newLength;*/public native void setLength(long newLength) throws IOException;/*** 关闭此流、释放与此流有关的所有资源*/public void close() throws IOException {if (channel != null)channel.close();close0();}//  一些方法是从DataInputStream/DataOutputStream中剽窃来的。。。/*** 读取一个boolean型数据*/public final boolean readBoolean() throws IOException {int ch = this.read();if (ch >> 8) & 0xFF);write((v >>> 0) & 0xFF);//written += 2;}/*** 将一个char写入文件*/public final void writeChar(int v) throws IOException {write((v >>> 8) & 0xFF);write((v >>> 0) & 0xFF);//written += 2;}/*** 将一个int写入文件*/public final void writeInt(int v) throws IOException {write((v >>> 24) & 0xFF);write((v >>> 16) & 0xFF);write((v >>>  8) & 0xFF);write((v >>>  0) & 0xFF);//written += 4;}/*** 将一个long写入文件*/public final void writeLong(long v) throws IOException {write((int)(v >>> 56) & 0xFF);write((int)(v >>> 48) & 0xFF);write((int)(v >>> 40) & 0xFF);write((int)(v >>> 32) & 0xFF);write((int)(v >>> 24) & 0xFF);write((int)(v >>> 16) & 0xFF);write((int)(v >>>  8) & 0xFF);write((int)(v >>>  0) & 0xFF);//written += 8;}/*** 将一个long写入文件*/public final void writeFloat(float v) throws IOException {writeInt(Float.floatToIntBits(v));}/*** 将一个double写入文件。*/public final void writeDouble(double v) throws IOException {writeLong(Double.doubleToLongBits(v));}/*** 将一个字符串转换成一串有序字节写入*/public final void writeBytes(String s) throws IOException {int len = s.length();byte[] b = new byte[len];s.getBytes(0, len, b, 0);writeBytes(b, 0, len);}/*** 将一个字符串以一串有序字符写入文件中*/public final void writeChars(String s) throws IOException {int clen = s.length();int blen = 2*clen;byte[] b = new byte[blen];char[] c = new char[clen];s.getChars(0, clen, c, 0);for (int i = 0, j = 0; i >> 8);b[j++] = (byte)(c[i] >>> 0);}writeBytes(b, 0, blen);}/*** 调用DataOutputStream的 writeUTF(String str, DataOutput out) 将一个字符串写入文件。*/public final void writeUTF(String str) throws IOException {DataOutputStream.writeUTF(str, this);}private static native void initIDs();private native void close0() throws IOException;static {initIDs();}}

更多IO内容:java_io 体系之目录

Java_io体系之RandomAccessFile简介、走进源码及示例——20相关推荐

  1. Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例——16

    Java_io体系之BufferedWriter.BufferedReader简介.走进源码及示例--16 一:BufferedWriter 1.类功能简介: BufferedWriter.缓存字符输 ...

  2. Java_io体系之CharArrayReader、CharArrayWriter简介、走进源码及示例——13

    转载自   Java_io体系之CharArrayReader.CharArrayWriter简介.走进源码及示例--13 一:CharArrayReader 1.类功能简介: 字符数组输入流car  ...

  3. Java_io体系之PipedInputStream、PipedOutputStream简介、走进源码及示例——06

    Java_io体系之PipedInputStream/PipedOutputStream简介.走进源码及示例--06 --管道输出流.必须建立在管道输入流之上.所以先介绍管道输出流.可以先看源码或者总 ...

  4. Java_io体系之PipedWriter、PipedReader简介、走进源码及示例——14

    Java_io体系之PipedWriter.PipedReader简介.走进源码及示例--14 --管道字符输出流.必须建立在管道输入流之上.所以先介绍管道字符输出流.可以先看示例或者总结.总结写的有 ...

  5. linux内核体系学习路径_Linux内核分析(一)linux体系简介|内核源码简介|内核配置编译安装...

    从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1. Linux体系结构简介 ...

  6. ThreadLocal 简介 案例 源码分析 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  7. Android View体系(五)从源码解析View的事件分发机制

    Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Sc ...

  8. UCML-领先的B/S应用快速开发工具,基于组件重用和应用框架重用,支持.NET体系,直接生成C#源码;

    UCML-领先的B/S应用快速开发工具,基于组件重用和应用框架重用,支持.NET体系,直接生成C#源码:UCML涵盖了一个WEB应用系统业务开发的全过程,包括数据访问层(O/R映射)定义.业务框架开发 ...

  9. 编译器 llvm clang 源码转换示例

    编译器 llvm clang 源码转换示例 从git获取llvm项目的源码方式: git clone https://github.com/llvm/llvm-project.git 下载源码后,进入 ...

最新文章

  1. OpenNMS Log Correlator
  2. python使用缩进来体现代码之间的逻辑关系-Python使用缩进来体现代码之间的逻辑关系。...
  3. ORA-01810: 格式代码出现两次
  4. 微信小程序uni.switchTab传参获取不到;小程序跳转到tabBar页并传参;uni-app微信小程序获取tabBar页面参数失败;uni-app微信小程序tabBar页面onLoad不执行
  5. charles抓包工具使用指南
  6. springboot:web开发-Thymeleaf
  7. Git建立远程代码仓库和本地代码仓库
  8. Sql中Output参数用法和分页存储过程
  9. 【R语言报错解决】—存在非数值型变量,Error in c_max * c_min : non-numeric argument to binary operator,如何在数据导入后转为数值型变量?
  10. xlsx 解析excel 后渲染到表格里(前端实现 解析excel渲染到表格)
  11. 服务器做虚拟网吧,一种基于游戏的虚拟网吧实现方法
  12. mysql怎么子查询_在mysql中如何进行子查询?
  13. 高级Android开发进阶之路,你需要掌握的几个关键技术!
  14. 计算机分子模拟的意义包括,计算机分子模拟
  15. 五、量子纠错编码的原理
  16. markdown 教程一
  17. mapbox制作动态地图——storytelling(附html代码)
  18. net-java-php-python-医药库存管理系统计算机毕业设计程序
  19. Java学习打卡第七天——[再谈Collection之Set,TreeSet,泛型Generic的简介和使用]
  20. 小i机器人闪耀首届长三角科交会,展示真实智能生活

热门文章

  1. Java——String类中的compareTo方法总结
  2. mysql主从复制、redis基础、持久化和主从复制
  3. 【转】Android studio安装与配置
  4. shlve模块 序列化 python任意的数据
  5. TOPCODER SAM 686 div1 300
  6. StringBuilder/StringBuffer类
  7. JavaScript 高级篇之DOM文档,简单封装及调用、动态添加、删除样式(推荐七)
  8. 齐次线性方程组的解、SVD、最小二乘法
  9. 计算机也可以看“视频”,理解“视频”
  10. OpenStack技术峰会PPT集萃