通过前面的学习我们知道,如果准备读文件,需要建立指向该文件的输入流;如果准备写文件,需要建立指向该文件的输出流。那么,能否建立一个流,通过该流既能读文件也能写文件呢?这正是本节要介绍的随机流。
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、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程