本篇介绍在io包中但不属于前面介绍的字节流和字符流体系的RandomAccessFile类,这里的不属于的意思是RandomAccessFile直接继承于Object,与InputStream和OutputStream没有继承关系。
RandomAccessFile有随机读取和写入文件的功能,可以跳到文件的任何位置读取或者写入,原因在于RandomAccessFile类持有一个文件位置指针,通过操纵这个指针的自由移动来实现随机访问功能。
与RandomAccessFile类相比,字节流与字符流的文件处理流就显得有局限性。例如在FileInputStream和Reader中通过mark和reset方法可以实现重复读,skip方法可以跳过指定字节数或字符数不读。FileOutputStream写入文件时只能覆盖原文件内容,Writer也只是提供appendt方法实现在原文件末尾写入的功能。即字节流和字符流都不具有随机访问功能。
要认识一个类还是先看一下API,然后根据API写一下测试程序执行感受一下,印象更深刻一些。
构造函数:
//name-文件路径 mode-访问模式
public RandomAccessFile(String name, String mode) throws FileNotFoundException;
//file-File对象 mode-访问模式
public RandomAccessFile(File file, String mode) throws FileNotFoundException;
其中访问模式有四种,分别为:
- r:以只读的方式打开文件,任何写入操作都会抛IOException异常;
- rw:以读写方式打开文件,可以读取和写入,指定路径文件不存在会创建此文件;
- rws:以读写方式打开文件,与rw方式相比,文件内容或元数据的每次更新都同步写入到底层设备;
- rwd:以读写方式打开文件,与rw方式相比,文件内容的每次更新都同步写入到底层设备。
主要方法:
//获取与此流关联的文件描述符
public final FileDescriptor getFD() throws IOException;
//获取NIO中的“通道”,后续NIO文章中会详细介绍
public final FileChannel getChannel();
//读取一个字节
public int read() throws IOException;
//将读取的数据转换为字节数组下标为off的元素开始len个字节
public int read(byte b[], int off, int len) throws IOException;
//读取的数据放入字节数组中
public int read(byte b[]) throws IOException;
//从文件的位置指针开始读取b.length个字节到字节数组
public final void readFully(byte b[]) throws IOException;
//从文件的位置指针开始读取len个字节到字节数组,从下标off开始
public final void readFully(byte b[], int off, int len) throws IOException;
//跳过n个字节
public int skipBytes(int n) throws IOException;
//写入一个字节
public void write(int b) throws IOException;
//将字节数组写入到文件中,从文件的位置指针开始写入
public void write(byte b[]) throws IOException;
//将字节数组从下标off开始的len个元素写入到文件中,从文件的位置指针开始写入
public void write(byte b[], int off, int len) throws IOException;
//获取文件的位置指针
public native long getFilePointer() throws IOException;
//将文件的位置指针调整到指定位置
public void seek(long pos) throws IOException;
//获取文件长度
public native long length() throws IOException;
//设置文件长度
public native void setLength(long newLength) throws IOException;
//关闭文件流
public void close() throws IOException;
//从文件中读取一个boolean值,还有读取整型值,读取字节值等其他类型的方法就不写了
public final boolean readBoolean() throws IOException;
//从文件中读取下一行文本
public final String readLine() throws IOException;
//从文件中读取字符串
public final String readUTF() throws IOException;
//写入一个boolean值,还有写入其他类型的方法也不写了
public final void writeBoolean(boolean v) throws IOException;
//写入一个字符串
public final void writeUTF(String str) throws IOException;
需要注意的是write()一系列方法写入时如果构造函数传入的文件不存在则创建该文件然后再写入。
测试程序及输出结果:
//测试程序
public static void main(String[] args) {
RandomAccessFile raf;
try {
raf = new RandomAccessFile("D:\\RandomAccessFile\\testFile.txt","rw");
byte[] bytes = {'1','2','3','4','5','\n','6','7','8','9','0'};
//写入文件
raf.write(bytes);
System.out.println("该文件的长度为:"+raf.length());
System.out.println("获取位置指针偏移量:"+raf.getFilePointer());
System.out.println("******设置位置指针偏移量为2******");
raf.seek(2);
System.out.println("下一行文本:"+raf.readLine());
System.out.println("******设置位置指针偏移量为0******");
raf.seek(0);
System.out.println("下一行文本:"+raf.readLine());
raf.write('a');
System.out.println("获取位置指针偏移量为:"+raf.getFilePointer());
raf.skipBytes(2);
System.out.println("获取位置指针偏移量为:"+raf.getFilePointer());
raf.seek(1);
byte[] byteArr = new byte[(int) (raf.length()-raf.getFilePointer())];
raf.read(byteArr);
System.out.println("读取的文件内容为:"+new String(byteArr,0,byteArr.length));
} catch (IOException e) {
e.printStackTrace();
}
//输出结果
该文件的长度为:11
获取位置指针偏移量:11
******设置位置指针偏移量为2******
下一行文本:345
******设置位置指针偏移量为0******
下一行文本:12345
获取位置指针偏移量为:7
获取位置指针偏移量为:9
读取的文件内容为:2345
a7890