通过前面的学习我们知道,如果准备读文件,需要建立指向该文件的输入流;如果准备写文件,需要建立指向该文件的输出流。那么,能否建立一个流,通过该流既能读文件也能写文件呢?这正是本节要介绍的随机流。
RandomAccessFile类创建的流称做随机流,与前面的输入、输出流不同的是,RandomAccessFile类既不是InputStream类的子类,也不是OutputStream类的子类。但是RandomAccessFile类创建的流的指向既可以作为流的源,也可以作为流的目的地,换句话说,当准备对一个文件进行读写操作时,创建一个指向该文件的随机流即可,这样既可以从这个流中读取文件中的数据,也可以通过这个流写入数据到文件。
以下是RandomAccessFile类的两个构造方法:
1)RandomAccessFile(String name,String mode)
参数name用来确定一个文件名,给出创建的流的源,也是流目的地。参数mode取r(只读)或rw(可读写),决定创建的流对文件的访问权利。
2)RandomAccessFile(File file,String mode)
参数file是一个File对象,给出创建的流的源,也是流目的地。参数mode取r(只读)或rw(可读写),决定创建的流对文件的访问权利。
注意:RandomAccessFile流指向文件时,不刷新文件。
RandomAccessFile类中有一个方法seek(long a)用来定位RandomAccessFile流的读写位置,其中参数a确定读写位置距离文件开头的字节个数。另外流还可以调用getFilePointer()方法获取流的当前读写位置。RandomAccessFile流对文件的读写比顺序读写更为灵活。
例如,把几个int型整数写入到一个名字为tom.dat文件中,然后按相反顺序读出这些数据:
import java.io.*;
public class Main {
public static void main(String args[]) {
RandomAccessFile inAndOut = null;
int data[] = {1,2,3,4,5,6,7,8,9,10};
try {
inAndOut = new RandomAccessFile("tom.dat","rw");
for(int i=0;i<data.length;i++) {
inAndOut.writeInt(data[i]);
}
for(long i = data.length-1;i>=0;i--) {
inAndOut.seek(i*4);
System.out.printf("\t%d",inAndOut.readInt());
/*
一个int型数据占4个字节,inAndOut从文件的第36个字节读取最后面的一个整数,每隔4个字节往前读取一个整数
*/
}
inAndOut.close();
}
catch(IOException e) {}
}
}RandomAccessFile流的常用方法如下:
| 方法 | 说明 |
| close() | 关闭文件 |
| getFilePointer() | 获取当前读写的位置 |
| length() | 获取文件的长度 |
| read() | 从文件中读取一个字节的数据 |
| readBoolean() | 从文件中读取一个布尔值,0代表false;其他值代表true |
| readByte() | 从文件中读取一个字节 |
| readChar() | 从文件中读取一个字符(2个字节) |
| readDouble() | 从文件中读取一个双精度浮点值(8 个字节) |
| readFloat() | 从文件中读取一个单精度浮点值(4个字节) |
| readFully(byte b[]) | 读b.length字节放入数组b,完全填满该数组 |
| readInt() | 从文件中读取一个int值(4个字节) |
| readLine() | 从文件中读取一个文本行 |
| readLong() | 从文件中读取一个长型值(8个字节) |
| readShort() | 从文件中读取一个短型值(2个字节) |
| readUnsignedByte() | 从文件中读取一个无符号字节(1个字节) |
| readUnsignedShort() | 从文件中读取一个无符号短型值(2个字节) |
| readUTF() | 从文件中读取一个UTF字符串 |
| seek(long position) | 定位读写位置 |
| setLength(long newlength) | 设置文件的长度 |
| skipBytes(int n) | 在文件中跳过给定数量的字节 |
| write(byte b[]) | 写b.length个字节到文件 |
| writeBoolean(boolean v) | 把一个布尔值作为单字节值写入文件 |
| writeByte(int v) | 向文件写入一个字节 |
| writeBytes(String s) | 向文件写入一个字符串 |
| writeChar(char c) | 向文件写入一个字符 |
| writeChars(String s) | 向文件写入一个作为字符数据的字符串 |
| writeDouble(double v) | 向文件写入一个双精度浮点值 |
| writeFloat(float v) | 向文件写入一个单精度浮点值 |
| writeInt(int v) | 向文件写入一个int值 |
| writeLong(long v) | 向文件写入一个长型int值 |
| writeShort(int v) | 向文件写入一个短型int值 |
| writeUTF(String s) | 写入一个UTF字符串 |
注意:RandomAccessFile流的readLine()方法在读取含有非ASCⅡ字符的文件时,比如含有汉字的文件,会出现“乱码”现象。因此,需要把readLine()读取的字符串用“iso-8859-1”编码重新编码存放到byte数组中,然后再用当前机器的默认编码将该数组转化为字符串,操作如下:
1.读取
String str = in.readLine();
2.用“iso-8859-1”重新编码
byte b[] = str.getBytes("iso-8859-1");3.使用当前机器的默认编码将字节数组转化为字符串
String content = new String(b);
如果机器的默认编码是“GB2312”,那么
String content = new String(b);
等同于
String content = new String(b,"GB2312");
例如:
import java.io.*;
public class Main {
public static void main(String args[]) {
RandomAccessFile in = null;
try {
in = new RandomAccessFile("Main.java","rw");
long length = in.length(); //获取文件的长度
long position = 0;
in.seek(position); //将读取位置定位到文件的起始
while(position<length) {
String str = in.readLine();
byte b[] = str.getBytes("iso-8859-1");
str = new String(b);
position = in.getFilePointer();
System.out.println(str);
}
}
catch(IOException e) {}
}
}C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程