RandomAccessFile是Java中输入/输出流体系中功能最丰富的文件内容访问类,它提供很多方法来操作文件,包括读写支持,与普通的IO流相比,它最大的特别之处就是支持任意访问的方式,程序可以直接跳到任意地方来读写数据(根据指针来实现)。
RandomAccessFile的超类是Object,而其他输入/输出流的超类是Stream(InputStream/OutputStream);
java.io.RandomAccessFile
-
创建RandomAccessFile实例
别忘了导包!以后就不会专门说明了!!!
代码示例:
/*
* RandomAccessFile raf = new RandomAccessFile(String name,String mode)
* @param name : 要操作的文件名,若是不存在则创建新的文件
* @param mode : r --只读模式 调用文件的任何 write 方法都将导致抛出 IOException
* wr --读写模式 (这两种模式常用)
*/
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException { //io操作会有异常产生,在本阶段异常暂不做介绍,以后详解
System.out.println("程序开始!");
/*
* RAF的常用构造方法:
* RandomAccessFile(String path,String mode)
* RandomAccessFile(File file,String mode)
*
* 第二个参数为模式,常用的为"r","rw"
* 需要注意,若指定文件不存在,那么若模式为"rw"时,RAF会自
* 动创建该文件,但如果模式为"r",则会抛出
* FileNotFoundException(继承了IOException)异常
* 也可以创建一个文件(File file)
*
* 在真实的项目环境下,为了兼容多种设备环境,若是文件使用绝对路径(文件的准确位置)
* 那么只能在同种平台使用比如:
* D:\demo\demo.txt 在Linux中没有D:这个概念
* 所以为了跨平台(一次编写到处运行)文件的路径一般为相对路径
* ./代表当前目录(不写也可)
* ../回退到上层目录
* ./dir1/dir2/test.txt 代表 当前dir1目录下的dir2目录中的test.txt 比如:src/image/girl.png
*
*/
RandomAccessFile raf =
new RandomAccessFile("./raf.dat", "r");
System.out.println("程序结束!");
raf.close();
}
}
-
常用API
- void write(int b) 向文件中写入指定字节 默认向文件中写入1个字节 写入的是给定的int值所对应的2进制“低8位”
- void write(byte[] b) 向文件中写入指定的块字节(字节数组)
- void read() 从此文件中读取一个字节
- void read(byte[] b) 从此文件中按块字节(字节数组),读取文件
- String 提供了讲字符串转换为字节的方法 getBytes() 返回的是个字节数组
- 重载的getBytes(Charset charset) 转换为指定字符集的字节数组
- void close() 关闭RandomAccessFile流
int是4个字节,32位的2进制数。int 0 ==> 2进制表示:"00000000(高8位) 00000000 00000000 00000000(低8位)"
int低8位的最大值为255:"00000000 00000000 00000000 11111111",超过范围自动进位溢出!!!- long getFilePointer() 获取指针位置 native修饰的本地方法
- void seek() 移动文件指针位置
- 读写 8大基本类型 write/read+基本数据类型修饰首字母大写 如:
- 写:
- writeDouble() 写双精度浮点数
- writeInt() 写整数
- writeLong() 写长整型
- ...
- 读:
- readInt() 读取int
代码示例:
/**
* 向文件中写入数据
* void write()
* 向文件中写入1个字节 写入的是给定的int值所对应的2进制“低8位”
* int 4个字节 每个字节是8位 共32位 最多写入255个字节 "11111111"
* void close() 关闭RandomAccessFile流
* 进行io操作 要及时关闭 防止增加内存负担 ,造成效率消耗
*
*/
public class WriteDemo {
public static void main(String[] args) throws IOException {
//创建实例
RandomAccessFile raf =
new RandomAccessFile("./raf.dat", "rw");
//只写二进制的低8位 高位移除 一次性写入200个字节,
raf.write(200);
//打桩测试
System.out.println("写入成功");
//关闭流 及时释放资源
raf.close();
}
}
/**
* void write(byte[] data)
* 一次性将给定的字节数组中所有字节写入文件
*/
public class WriteStringDemo {
public static void main(String[] args) throws IOException {
//实例
RandomAccessFile raf =
new RandomAccessFile("raf.txt", "rw");
String str = "hello,world";
//将要写入的字符串转换为字节(数组形式)
byte[] data = str.getBytes("utf-8");
/**
* String 提供了转换为字节的方法
* byte[] getBytes()
* 将当前字符串按照系统默认字符集转换为一组字节
*/
//写入文件
raf.write(data);
raf.write("Welcome To China".getBytes("utf-8"));
System.out.println("写出完毕");
raf.close();
}
}
读写基本数据类型以及基于文件指针的读写操作:
package raf;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* RandomAccessFile读写基本类型数据以及基于指针读写的操作
* long getFilePointer() 获取指针位置 native修饰的本地方法
* native关键字说明其修饰的方法是一个原生态方法,
* 方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。 (在此只做了解)
*
* void seek() 移动文件指针位置
* 文件在写入完毕之后,指针会在文件的末尾,要想读取数据要将指针移动到文件的开头
*
* 读写 8大基本类型 write/read+基本数据类型修饰[首字母大写]() 如:
* 写:
* writeDouble() 写双精度浮点数
* writeInt() 写整数
* writeLong() 写长整型
* ...
* 读:
* readInt() 读取int
* ...
*
*/
public class RandomAccessFileDemo02 {
public static void main(String[] args)
throws IOException {
RandomAccessFile raf =
new RandomAccessFile("raf.txt", "rw");
System.out.println("pointer:"+raf.getFilePointer());
int max = Integer.MAX_VALUE;
raf.write(max>>24);
System.out.println("pointer:"+raf.getFilePointer());
raf.write(max>>16);
raf.write(max>>8);
raf.write(max);
System.out.println("pointer:"+raf.getFilePointer());
raf.writeInt(max);
System.out.println("pointer:"+raf.getFilePointer());
raf.writeDouble(123.123);
System.out.println("pointer:"+raf.getFilePointer());
raf.writeLong(100L);
System.out.println("pointer:"+raf.getFilePointer());
System.out.println("写出完毕");
//指针移回开始 0
raf.seek(0);
//读取 文件中 int 数据
int i = raf.readInt();
System.out.println(i);
System.out.println("pointer:"+raf.getFilePointer());
//读取 文件中long 值
raf.seek(16);
long l = raf.readLong();
System.out.println(l);
System.out.println("pointer:"+raf.getFilePointer());
//重写 文件中 double 值
raf.seek(8);
raf.writeDouble(456.456);
//读取 文件中 double 值
raf.seek(8);
double d = raf.readDouble();
System.out.println(d);
System.out.println("pointer:"+raf.getFilePointer());
//关闭IO
raf.close();
}
}
小案例1_复制文件:
/**
* int read(byte[] date)
* 一次性从文件中读取给定的字节数组总长度的字节量
* 并将读取到的字节顺序存入到该数组中
* 返回值为实际读取到的字节量,若返回值为-1,则表
* 示读取到了文件末尾(每次也没有读取到任何自己)
*
* void write(byte[] data,int offset,int len)
* 将给定的字节数组 从下标offset处开始 连续len个字节一次性
* 写入到文件中
*
*/
public class CopyDemo2 {
public static void main(String[] args) throws IOException {
/* 源文件 */
RandomAccessFile src =
new RandomAccessFile("src/demo.txt", "r");
/* 目标文件 */
RandomAccessFile desc =
new RandomAccessFile("demo_cpoy.txt", "rw");
/* 用于记录每次实际读取到的字节数 */
int len = -1;
/* 保存每次读取到的字节 10k */
byte[] data = new byte[1024*10];
long start = System.currentTimeMillis();
/* 块读取源文件 当读取的不是文件末尾时循环读取 */
while((len = src.read(data))!=-1){
/* 块写入目标文件 */
desc.write(data,0,len);
}
long end = System.currentTimeMillis();
System.out.println("复制完毕!耗时"+(end-start)+"ms");
src.close();
desc.close();
}
}
小案例2_记事本:
/**
* 简易的记事本工具
* 需求:
* 1.向指定的文件写入内容(用户操作)
* 2. 在用户输入"exit"(单行)时退出
*/
public class Notepad {
public static void main(String[] args) throws IOException {
writeAgain();
}
public static void writeAgain() throws IOException{
//创建接收器
Scanner scan = new Scanner(System.in);
System.out.println("请输入要操作的文件名:");
//接收用户需要操作的文件名
String fileName = scan.nextLine();
//文件实例
RandomAccessFile raf =
new RandomAccessFile(fileName, "rw");
System.out.println("请开始输入内容:");
while(true){
//接收用户输入的内容
String line = scan.nextLine();
//输入exit退出
if("exit".equals(line)){
break;
}
//向文件中写入内容
raf.write(line.getBytes("utf-8")); //指定编码写入
}
System.out.println("再见");
raf.close();
scan.close();
}
}