RandomAccessFile类可以说是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,可以跳转到文件的任意位置处读写数据。在要访问一个文件的时候,不想把文件从头读到尾,而是希望像访问一个数据库一样地访问一个文本文件,这时使用RandomAccessFile类就是最佳选择。
RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当读写n个字节后,文件指示器将指向这n个字节后的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。
RandomAccessFile类是一个特殊IO流,它不能访问除File以外的其他的任何IO设备,只是对File进行操作。这个类的特点是随机访问File类的任何一个位置开始读取。其RandomAccessFile类内部有一个类似与指针的指示器,控制这它访问开始的位置或者当前访问的位置。很多的断点下载都是通过他的原理来实现的。
RandomAccessFile类的常用实现就是读取一个等长的数据,因为每一条数据都是等长的,我们可以直接在第2条数据或者第200条数据开始读取。就像我们java的加密一样,我们双方都知道一个特定的格式了,所以你加密后的文件在我的系统中能够被读取。等长数据就是字符长度一定的数据。下面我用一个例子来具体解释这个类一些基本方法和实现。
public class Employee {
private String name;
private int age;
public static final int len = 12;
/*
* 创建这个类的目的在于,创建一个等长的数据。
*/
public Employee() {
}
public Employee(String name, int age) {
this.setName(name);
this.setAge(age);
}
public String getName() {
return name;
}
/**
* 这个里面就是控制name属性字符长度不会超出8个字符长度。
* @param name
*/
public void setName(String name) {
StringBuilder builder = null;
if (null != name && (len - 4) <= name.length()) {
builder = new StringBuilder(name);
} else if (null == name) {
builder = new StringBuilder(len - 4);
} else {
builder = new StringBuilder(name);
while (builder.length() < (len - 4)) {
builder.append("/u0000");
}
}
builder.setLength(len - 4);
this.name = builder.toString();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
准备工作我们做好以后,我们开始写一个我们测试用的类如下:
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
public class EmplyoeeTest {
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws Exception {
/**
* 创建3条等长数据
*/
Employee e1=new Employee("田智文",12);
Employee e2=new Employee("abcdefghijklmnopqrstuvwsyz",23);
Employee e3=new Employee("wangwu",66);
/**
* 打开一个文件,如果没有这个文件他会为我们创建这个文件,rw是一读写的方式打开的,这里区分以只读的方式打开
* 为什么使用writeChars方法,是因为我们java里面一个汉字和一个英文都是一样的长度,字节数也是一样的,但是
* 在系统中一个汉字的字节数为2个字节,而英文的字节数为1个字节。我们使用这个方法,就是让一个英文的字节数也
* 占2个字节。
*/
RandomAccessFile accessFile=new RandomAccessFile("employee.txt","rw");
accessFile.writeChars(e1.getName());
accessFile.writeInt(e1.getAge());
accessFile.writeChars(e2.getName());
accessFile.writeInt(e2.getAge());
accessFile.writeChars(e3.getName());
accessFile.writeInt(e3.getAge());
accessFile.close();
RandomAccessFile read=new RandomAccessFile("employee.txt","r");//自读的方式打开文件
read.seek((Employee.len-4) * 2 + 4);//这个方法是RandomAccessFile类里面的指针的一定,这个方法绝对移动到一个位置。
//Employee.len-4) * 2 + 4,是因为我写入的时候把一个英文字节写如2个字节的位置,所以长度自然要加一倍,下面也是同理
StringBuilder builder=new StringBuilder(); //String是固定不变的,在进行字符串连接的时候是新建一个字符串,进行连接后,最后赋值,如果对String赋值多次,就会在内存中保存多个这个对象的副本,浪费系统资源;StringBuilder是可变的,不用生成中间对象,拼接字符串比较多,或字符串的长度比较长时有较高的效率。StringBuilder的内存空间不够也要扩容,如果分配的空间远远大于需要量,也很浪费所以,初始化StringBuilder的时候最好根据需要设置容量,避免浪费。
for (int i = 0; i < (Employee.len-4); i++) {
builder.append(read.readChar());
}
System.out.println("第二名员工的名字:"+builder.toString().trim()+"---年龄:"+read.readInt()); //trim()从此实例的开始位置和末尾移除空白字符的所有匹配项。
read.skipBytes((Employee.len-4) * 2);//这个方法是相对当前指针位置的移动
System.out.println("第三名员工的年龄:"+read.readInt());
read.seek(0);
StringBuilder builder1=new StringBuilder();
for (int i = 0; i < (Employee.len-4); i++) {
builder1.append(read.readChar());
}
System.out.println("第一名员工的名字:"+builder1.toString().trim()+builder1.toString().getBytes().length+"---年龄:"+read.readInt());
read.close();
}
}
转载
http://blog.csdn.net/tianzhw/article/details/6117005