javaIO RandomAccessFile类随机读写

RandomAccessFile类的主要功能是完成随机读取功能,可以读取指定位置的内容。

File类只是针对文件本身进行操作的,而如果要想对文件内容进行操作,则可以使用RandomAccessFile类,RandomAccessFile属于随机读取类,可以随机读取一个文件中指定位置的数据

1. 构造方法

RandomAccessFile(File file, String mode) 
          创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

第二个参数打开文件的模式,有以下四种:注意没有只写“w”方式

(1) "r" 以只读方式打开。

(2)"rw"以读写方式打开,如果该文件尚不存在,则尝试创建该文件。

(3) "rws"

(4)"rwd"

2.相关方法

(1) long getFilePointer():返回文件记录指针的当前位置,

(2) void seek(long pos):将文件记录指针定位到pos位

(3) void close():关闭文件,文件访问结束后一定要关闭文件,否则会发生意想不到的错误。

(4) long length() :返回此文件的长度(字节)。

(5) void setLength(long newLength)  throws IOException  :设置文件的长度

    如果 length 方法返回的文件的现有长度大于 newLength 参数,则该文件将被截短。在此情况下,如果 getFilePointer 方法返回的文件偏移量大于 newLength,那么在返回此方法后,该偏移量将等于 newLength。

    如果 length 方法返回的文件的现有长度小于 newLength 参数,则该文件将被扩展。在此情况下,未定义文件扩展部分的内容。

(6) 写方法:write(),writeBoolean(),writeByte(),writeBytes(),writeChar(),writeChars()
void write(byte[] b) 
          //将 b.length 个字节从指定 byte 数组写入到此文件,并从当前文件指针开始。 
void write(byte[] b, int off, int len) 
         //将 len 个字节从指定 byte 数组写入到此文件,并从偏移量 off 处开始。 
void write(int b) 
          //向此文件写入指定的字节。 
void writeBoolean(boolean v) 
          //按单字节值将 boolean 写入该文件。 
void writeByte(int v) 
          //按单字节值将 byte 写入该文件。 
void writeBytes(String s) 
          //按字节序列将该字符串写入该文件。 
void writeChar(int v) 
          //按双字节值将 char 写入该文件,先写高字节。 
 void writeChars(String s) 
          //按字符序列将一个字符串写入该文件。 
 void writeDouble(double v) 
          //使用 Double 类中的 doubleToLongBits 方法将双精度参数转换为一个 long,然后按八字节数量将该 long 值写入该文件,先定高字节。 
 void writeFloat(float v) 
          //使用 Float 类中的 floatToIntBits 方法将浮点参数转换为一个 int,然后按四字

(7) 读方法:read(),readBoolean(),readByte(),readChar(),readDouble(),readFloat(),readFully(),readInt(),readLine()

int read() 
          从此文件中读取一个数据字节。 
int read(byte[] b) 
          将最多 b.length 个数据字节从此文件读入 byte 数组。 
int read(byte[] b, int off, int len) 
          将最多 len 个数据字节从此文件读入 byte 数组。 
boolean readBoolean() 
          从此文件读取一个 boolean。 
byte readByte() 
          从此文件读取一个有符号的八位值。 
char readChar() 
          从此文件读取一个字符。 
double readDouble() 
          从此文件读取一个 double。 
float readFloat() 
          从此文件读取一个 float。 
void readFully(byte[] b) 
          将 b.length 个字节从此文件读入 byte 数组,并从当前文件指针开始。 
void readFully(byte[] b, int off, int len) 
          将正好 len 个字节从此文件读入 byte 数组,并从当前文件指针开始。 
int readInt() 
          从此文件读取一个有符号的 32 位整数。 
String readLine() 
          从此文件读取文本的下一行。 
long readLong() 
          从此文件读取一个有符号的 64 位整数。 
short readShort() 
          从此文件读取一个有符号的 16 位数。 
int readUnsignedByte() 
          从此文件读取一个无符号的八位数。 
int readUnsignedShort() 
          从此文件读取一个无符号的 16 位数。 
String readUTF() 
          从此文件读取一个字符串。 
3. 实例
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Test
{
	static void testWrite() throws IOException
	{
		File file=new File(".\\test.txt");
		if(!file.exists())
		{
			file.createNewFile();
		}
		//随机文件对象
		RandomAccessFile raf=new RandomAccessFile(file, "rw");
		System.out.println("文件指针位置:"+raf.getFilePointer());
		raf.writeInt(20);//写入一个int
		System.out.println("文件指针位置:"+raf.getFilePointer());
		raf.writeBoolean(true);//写入一boolean
		raf.close();//关闭文件
	}
	static void TestRead() throws IOException
	{
		File file=new File(".\\test.txt");
		//随机文件对象
		RandomAccessFile raf=new RandomAccessFile(file, "rw");
		int in = raf.readInt();//写入一个int
		System.out.println(in);
		boolean flag= raf.readBoolean();//写入一boolean
		System.out.println(flag);
		raf.close();//关闭文件
	}
	public static void main(String[] args) throws IOException
	{
		testWrite();//写文件
		TestRead();
	}
}

运行结果:

文件指针位置:0
文件指针位置:4
20
true
用记事本打开text.txt文件:


可以看见文件test.txt文件是乱码的,这是因为我们用RandomAccessFile写入的是一个字节一个字节的二进制信息。是二进制文件,不是txt文件,记事本无法解析所以乱码。

虽然是这样,但是我们可以在自己写代码来读文件。在上面的代码中TestRead();方法就是自定义的读文件方法。

4. 实例:对对象的读取和存储,要求

(1) 使用RandomAccessFile存储Student对象的一条条记录到文件中

(2) 然后从文件中读出一条条记录

(3) 读取第n条学生记录

代码:

学生类:

import java.io.IOException;
import java.io.RandomAccessFile;

public class Student
{
	String id;// 学号
	String name;// 名字
	String sex;// 性别
	int age;// 年龄
	public Student()
	{
	}
	public Student(String id, String name, String sex, int age)
	{
		this.id = id;
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	public void writeStudent(RandomAccessFile raf) throws IOException
	{
		raf.writeUTF(this.id);
		raf.writeUTF(this.name);
		raf.writeUTF(this.sex);
		raf.writeInt(this.age);
	}
	public void readStudent(RandomAccessFile raf) throws IOException
	{
		this.id = raf.readUTF();
		this.name = raf.readUTF();
		this.sex = raf.readUTF();
		this.age = raf.readInt();
	}
	@Override
	public String toString()
	{
		return "Student [id=" + id + ", name=" + name + ", sex=" + sex
				+ ", age=" + age + "]";
	}
	/**
	 * 获取到第n条学生记录
	 */
	public Student getTheNthStudent(RandomAccessFile raf, int n)
			throws IOException
	{
		if (n < 1)
		{
			System.out.println("n要大于1");
			return null;
		}

		Student student = new Student();
		raf.seek(0);
		n--;
		while (n >= 0)
		{
			student.readStudent(raf);// 读取一条记录
			n--;
		}
		return student;
	}
}

测试类:

public class TestRandomAccessFile
{
    public static void main(String[] args) throws IOException
    {
        File file=new File(".\\text2.txt");
        if(!file.exists())
        {
            file.createNewFile();
        }
        RandomAccessFile raf=new RandomAccessFile(file, "rw");//以读写方式打开
        Student student=new Student("B1000","小明名名","男",20);
        student.writeStudent(raf);
        System.out.println("当前文件指针位置:"+raf.getFilePointer());
        Student student1=new Student("B1001","小黄","男",20);
        student1.writeStudent(raf);
        System.out.println("当前文件指针位置:"+raf.getFilePointer());
        
        raf.seek(0);// 读取时,将指针重置到文件的开始位置。
        Student student2 = new Student();
        student2.readStudent(raf);//从文件中读取一条学生记录
        System.out.println(student2);
        System.out.println("当前文件指针位置:"+raf.getFilePointer());
        //读取一条记录后文件指针会前移到下一个学生记录
        student2.readStudent(raf);//从文件中读取一条学生记录
        System.out.println(student2);
        System.out.println("当前文件指针位置:"+raf.getFilePointer());
        raf.seek(0);//
        System.out.println("第2个学生的信息为:");
        student2 = student2.getTheNthStudent(raf, 2);
        System.out.println(student2);
        System.out.println("当前文件指针位置:"+raf.getFilePointer());
        
        raf.close();//关闭文件
        
    }
}

运行结果:

当前文件指针位置:30
当前文件指针位置:54
Student [id=B1000, name=小明名名, sex=男, age=20]
当前文件指针位置:30
Student [id=B1001, name=小黄, sex=男, age=20]
当前文件指针位置:54
第2个学生的信息为:
Student [id=B1001, name=小黄, sex=男, age=20]
当前文件指针位置:54

分析:可以看到RandomAccessFile具有很好的随机读写特性。可就算能设定文件指针的具体位置,但是在读取学生记录的时候,每条学生记录的长度(字节数),都不一定相等。所以到读取第n条学生记录的时候,我的做法是从头开始读取学生记录,一直循环读取,直到读取到第n条学生记录为止。


5.追加文件:

(1) 在上面程序的生成的文件末尾追加一条学生记录

(2) 显示文件中所有的学生记录

代码:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAcceessFileAdd
{
	//显示文件中的所有学生记录
	public static void printAllRadomAccessFile() throws IOException
	{
		File file=new File(".\\text2.txt");
		RandomAccessFile raf=new RandomAccessFile(file, "r");//以读写方式打开
		Student student=new Student();
		while(raf.getFilePointer()<raf.length())
		{
			student.readStudent(raf);//读取一条记录
			System.out.println(student);
		}
		raf.close();
				
	}
	public static void main(String[] args) throws IOException
	{
		File file=new File(".\\text2.txt");
		if(!file.exists())
		{
			file.createNewFile();
		}
		//打印文件中的所有学生记录
		printAllRadomAccessFile();
		RandomAccessFile raf=new RandomAccessFile(file, "rw");//以读写方式打开
		
		Student student=new Student("B1002","张三丰","男",20);
		raf.seek(raf.length());//指针移动到文件末尾
		student.writeStudent(raf);//添加一条学生记录
		System.out.println("--------------------");
		printAllRadomAccessFile();
	}
}

运行结果:

Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
--------------------
Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]

分析:可以看到插入之前文件中有三条记录,插入之后文件中有四条记录,追加成功。

6. 删除一条记录

(1) 输入要你要删除第几条记录

方法1 通过临时文件来实现:建立临时文件temp.txt,从记录文件test2.txt中读取记录,检查这条记录是不是要删除的那条,如果是的话就略过这条记录。直接读取下一条。如果不是要删除的记录,就把这条记录写入临时文件temp.txt中。遍历完成后临时文件中已经没有了你要删除的那条记录,然后把记录文件test2.txt删除掉。然后把临时文件重命名为test2.txt即可。

缺点:读写操作慢,占时间。

优点:少占内存。

方法2 通过数据结构,一开始就把所有的记录添加到ArrayList中,删除的时候把ArrayList中的学生对象删除掉。把记录文件的长度置零,然后再写入到记录文件中去即可。这样的好处就是在程序运行的时候,数据是在内存中的,访问修改起来很快,读写操作少。缺点是占内存。

代码:

(1) 方法一:通过临时文件重命名来删除一条记录。

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Scanner;

public class DeleteRAF
{
	//显示文件中的所有学生记录
	public static void printAllRadomAccessFile(File file) throws IOException
	{

		RandomAccessFile raf=new RandomAccessFile(file, "r");//以读写方式打开
		Student student=new Student();
		while(raf.getFilePointer()<raf.length())
		{
			student.readStudent(raf);//读取一条记录
			System.out.println(student);
		}
		raf.close();			
	}
	public static void main(String[] args) throws IOException
	{
		File file=new File(".\\text2.txt");
		//临时文件
		File TempFile=new File(".\\tempFile.txt");
		if(!TempFile.exists())
		{
			TempFile.createNewFile();
		}
		//打印文件中的所有学生记录
		printAllRadomAccessFile(file);
		RandomAccessFile raf=new RandomAccessFile(file, "r");//以只读的方式打开
		RandomAccessFile towrite=new RandomAccessFile(TempFile, "rw");//以读写的方式打开
		Scanner scanner=new Scanner(System.in);
		System.out.println("输入要删除第几条记录:");
		int deleteNum=scanner.nextInt();
		if(deleteNum<1)
		{
			System.out.println("记录数要大于1");
		}
		Student student=new Student();
		int count=0;//
		while(raf.getFilePointer()<raf.length())
		{
			student.readStudent(raf);//读取一条记录
			count++;//读到的记录数计数器加一
			if(count==deleteNum)//如果读到的这条记录是要删除掉的
			{
				continue;//跳过这条记录
			}
			student.writeStudent(towrite);//如果不是要删除的这条记录,就把这条记录写到临时文件中	
		}
		System.out.println("-----------------------------");
		printAllRadomAccessFile(TempFile);
		raf.close();
		towrite.close();
		file.delete();//删除原文件
		//把临时文件改名为test2.txt
		TempFile.renameTo(new File(".\\text2.txt"));
		System.out.println("---------------删除后的test2.txt文件为--------------");
		printAllRadomAccessFile(new File(".\\text2.txt"));
	}
}

运行结果:

Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
输入要删除第几条记录:
4
-----------------------------
Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
---------------删除后的test2.txt文件为--------------
Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]

可以看到这样的确可以删除掉一条记录。

(2) 方法2 借助集合框架,只有记录发生改变的时候才写文件,减少IO次数。

代码:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Scanner;

public class DeleteRAF2
{
	static ArrayList<Student> stuList=new ArrayList<Student>();
	public static void initializeList() throws IOException
	{
		File file =new File(".\\text2.txt");
		//以只读的方式打开文件
		RandomAccessFile raf=new RandomAccessFile(file,"r");
		
		while(raf.getFilePointer()<raf.length())
		{
			Student student=new Student();
			student.readStudent(raf);//从文件中读取一条记录
			stuList.add(student);//把这条记录生成的对象添加到集合中去。
		}
		raf.close();//关闭文件
	}
	public static void writeList(RandomAccessFile raf) throws IOException
	{
		//把集合中的所有Student对象写入到文件中
		for (Student student : stuList)
		{
			student.writeStudent(raf);
		}
	}
	//显示List中的所有学生
	public static void showAllStudent()
	{
		for (Student student : stuList)
		{
			System.out.println(student);
		}
	}
	public static void main(String[] args) throws IOException
	{
		initializeList();//初始化集合
		showAllStudent();
		System.out.print("输入你要删除的第几条记录:");
		Scanner scanner=new Scanner(System.in);
		int deleteNum=scanner.nextInt();
		stuList.remove((deleteNum-1));//从集合中删除这条记录
		System.out.println("---------------------");
		showAllStudent();
		RandomAccessFile raf=new RandomAccessFile(new File(".\\text2.txt"), "rw");
		raf.setLength(0);
		writeList(raf);
		raf.close();
	}
}

运行结果:

Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
Student [id=B1002, name=张三丰, sex=男, age=20]
输入你要删除的第几条记录:3
---------------------
Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]

可以看到使用ArrayList之后,删除操作我们可以直接掉用ArrayList的删除方法来删除记录(集合中的对象),只需要读写两次文件就可以了。代码量减少了,代码也很简洁。

7. 在任意位置添加一条记录。

(1) 方法1:借助临时文件,从记录文件中读取记录写入临时文件,并且计数,到要插入的位置时,写入要插入的记录。这时候临时文件中就比记录文件多了一条记录了。然后再接着从记录文件中把剩余的记录读取到临时文件中。最后删除记录文件,并且把临时文件重命名。

(2) 方法2:借助数据结构,刚开始读取记录文件初始化ArrayList,然后增加记录的时候,只需要调用ArrayListd的方法在ArrayList中添加一个对象就可,最后把ArrayList中的记录写到文件中集合。

借助ArrayList的好处就是,对文件的操作全部转换成了对ArrayList的操作。而ArrayList给我们提供好了各种函数我们只需要简单的调用即可实现。代码简介精炼。

代码:

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;

public class AddInAny
{
	static ArrayList<Student> stuList=new ArrayList<Student>();
	public static void initializeList() throws IOException
	{
		File file =new File(".\\text2.txt");
		//以只读的方式打开文件
		RandomAccessFile raf=new RandomAccessFile(file,"r");
		
		while(raf.getFilePointer()<raf.length())
		{
			Student student=new Student();
			student.readStudent(raf);//从文件中读取一条记录
			stuList.add(student);//把这条记录生成的对象添加到集合中去。
		}
		raf.close();//关闭文件
	}
	public static void writeList(RandomAccessFile raf) throws IOException
	{
		//把集合中的所有Student对象写入到文件中
		for (Student student : stuList)
		{
			student.writeStudent(raf);
		}
	}
	//显示List中的所有学生
	public static void showAllStudent()
	{
		for (Student student : stuList)
		{
			System.out.println(student);
		}
	}
	public static void main(String[] args) throws IOException
	{
		initializeList();
		showAllStudent();
		System.out.println("-------------插入一条记录后-------------");
		stuList.add(0,new Student("B10005","小蓝","男",19));
		showAllStudent();
		RandomAccessFile raf=new RandomAccessFile(new File(".\\text2.txt"), "rw");
		raf.setLength(0);
		writeList(raf);
		raf.close();
	}
}

运行结果:

Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
-------------插入一条记录后-------------
Student [id=B10005, name=小蓝, sex=男, age=19]
Student [id=B1000, name=小明名名, sex=男, age=20]
Student [id=B1001, name=小黄, sex=男, age=20]
可以看到只需要在main函数中改几条代码就可以实现了,借助集合这个数据结构来做的确实很方便。


总结:

(1) 上面以及把对RandomAccessFile的文件的操作,转换为对ArrayList的操作。对文件的增删改查,转换成对ArrayList的增删改查。

(2) 上面已经完成了对文件的增加和删除的操作,借助ArrayList来实现的话并不难。这里就不在列举了。

 



  • 9
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值