RandomAccessFile类是java提供的对文件内容的访问类,既可以读文件,也可以写文件。
RandomAccessFile类支持随机访问文件,也就是可以访问文件的任意位置。
(1)java的文件模型
在硬盘上的文件是以byte存储的,是数据的集合
(2)打开文件有两种模式
“rw”(读写) 可以对文件进行读写
“r”(只读) 只能对文件进行读操作
代码示例:RandomAccessFile raf = new RandomeAccessFile(file,"rw")
文件指针,打开文件的时候指针在开头 pointer=0;
(3)写方法
raf.write(int)--一次只能写一个字节(后8位),传入一个int类型,那么需要进行4次写操作写完后指针指向下一个位置,准备再次写入
(4)读方法
int b=raf.read()-----在指针在的位置读一个字节,然后把该字节操作成整数
(5)文件读写完一定要记得关闭io流(来自Oracle的官方警告)
具体代码示例:
package demo2;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.RandomAccess;
public class RafDemo {
public static void main(String[] args) throws IOException {
// 在内存中创建文件对象
File demo = new File("demo");// 不填路径则默认在工程文件夹下创建
// 如果文件(夹)不存在则创建文件(夹)
if (!demo.exists()) {
// 创建文件夹
demo.mkdir();
}
// 以demo文件夹作为父目录,创建一个raf.dat文件
File file = new File(demo, "raf.dat");
if (!file.exists()) {
// 不存在则创建
file.createNewFile();
}
// 进行读写操作
// 指定要读写的对象与选择读写模式
RandomAccessFile raf = new RandomAccessFile(file, "rw");
// 查看指针位置
System.out.println("第1次查看指针位置" + "前面有" + raf.getFilePointer() + "个字符");
// write一次只能写1个字节,所以只会将A的低八位写进去
raf.write('A');// 只写了一个字节进去
// 查看指针位置
System.out.println("第2次查看指针位置" + "前面有" + raf.getFilePointer() + "个字符");
raf.write('B');
// 将i写进去
System.out.println("第3次查看指针位置" + "前面有" + raf.getFilePointer() + "个字符");
int i = 0x7fffffff;
// 用write方法每次只能写一个字节,int是4个字节也就是32位,则要写四次
// 右移24位,则高八位变成低八位,就可以将高位写进去,如果看不懂这,可以先去看看二进制相关知识。
raf.write(i >>> 24);
raf.write(i >>> 16);
raf.write(i >>> 8);
raf.write(i);
System.out.println("第4次指针位置:" + "前面有" + raf.getFilePointer() + "个字符");
// 其实也有相应的方法可以直接写入int,上面的位移写入是他的底层原理
raf.writeInt(i);
// 尝试写入中文
String s = "中";// 在用输入法打出这个字符串的时候是使用java默认的utf-16be编码
//
byte[] gbk = s.getBytes("GBK");// 在这将其转换为gbk编码
raf.write(gbk);
// 查看文件长度
System.out.println("文件长度为" + raf.length() + "字节");
/*
* Java是双字节编码,采用的是utf-16be编码方式,
*
* 这里的write()写入A、B、i 都是采用的Java默认的utf-16be编码,
*
* 而utf-16be编码是中文和英文都占两个字节。
*
* 也就是A,B传进去之前是char型16位,本身是占两个字节,但每次只能传低八位进去,所以只传进去2个字节
*
* 又因为大小写字母在编码表中对应的编码都在byte类型范围内,所以不需要进行位移都可以完整传进去
*
* 而是整形,需要完整将i传进去需要传4次,每次以整形4个字节传进去,但每次只传进1个字节(低8位),所以i占了4个字节
*
* 后面的汉字“中”采用的gbk编码方式是中文占两个字节,英文占1个字节。所以“中”占用了2个字节
*
* 所以getBytes("gbk")指定了编码方式。
*
* 因为在文件的(手动查看)编码方式中char字符占2个字节,
*
* 所以A占2个字节,B占2个字节,int类的i占4字节,中占2字节,
*
* 所以文件长度为12个字节
*/
// 完整读取文件时必须从文件开始读取,也就是要将指针移到头部
raf.seek(0);
// 一次性读取,将读取到的内容都存储到字节数组中
// raf.length()返回的是long类型
// 创建byte数组来储存读取到的内容,数组长度由将要读取的文件长度决定
byte[] buf = new byte[(int) raf.length()];
// 从该文件读取最多数组长度个字节的数据到该字节数组。
raf.read(buf);
System.out.println(Arrays.toString(buf));
// 使用指定的编码将buf数组转换为字符串的形式输出,
String s1 = new String(buf, "GBK");
System.out.println(s1);// 输出结果出现乱码
/*
* 读取的时候是!整个!文件读取出来,
*
* 其中int类的i分开四个写,
*
* 所以计算机没法找到对应的编码,所以乱码了
*/
// 以16进制输出
for (byte b : buf) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
// 关闭文件io流,务必!
raf.close();
}
}