// DataInputStream类实现了DataInput接口,要想从文件中读入二进制数据, // 你需要将DataInputStream与某个字节源相结合,例如FileInputStream // 与此同时,要想写出二进制数据,可以使用实现了DataOutput接口的DataOutputStream类 // RandomAccessFile类同时实现了DataInput和DataOutput接口。 // 以下程序将三条记录写到一个数据文件中,然后以逆序将它们从文件中读回。 // 为了高效地执行,这里需要使用随机访问,因为我们需要首先读入第三条记录 // 让我们来计算每条记录的大小:我们将使用40个字符来 表示姓名字符串,因此每条记录包含100个字节: // 40字符 = 80字节,用于姓名 // 1 double = 8字节,用于薪水 // 3 int = 12字节,用于日期 package com.example.io; import java.io.DataInput; import java.io.DataOutput; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; public class RandomFileTest { public static void main(String[] args) { Employee[] staff = new Employee[3]; staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15); staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1); staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15); try { // 保存所有雇员记录到文件当中 DataOutputStream out = new DataOutputStream(new FileOutputStream("employee.dat")); for (Employee e : staff) { e.writeData(out); } out.close(); // 读取所有记录到新数组中 RandomAccessFile in = new RandomAccessFile("employee.dat", "r"); // 计算数组的尺寸 int n = (int) (in.length() / Employee.RECORD_SIZE); Employee[] newStaff = new Employee[n]; //反序读入雇员记录 for (int i = n - 1, j = 0; i >= 0; i--) { newStaff[j] = new Employee(); in.seek(i * Employee.RECORD_SIZE); newStaff[j].readData(in); j++; } in.close(); // 打印新读入数组记录内容 for (Employee e : newStaff) { System.out.println(e); } } catch (Exception e) { e.printStackTrace(); } } } class Employee { public Employee() { } public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); hireDay = calendar.getTime(); } public String getName() { return name; } public double getSalary() { return salary; } public Date getHireDay() { return hireDay; } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } @Override public String toString() { return "Employee{" + "name=" + name + ", salary=" + salary + ", hireDay=" + hireDay + '}'; } public void writeData(DataOutput out) throws IOException { DataIO.writeFixedString(name, NAME_SIZE, out); out.writeDouble(salary); GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(hireDay); out.writeInt(calendar.get(Calendar.YEAR)); out.writeInt(calendar.get(Calendar.MONTH) + 1); out.writeInt(calendar.get(Calendar.DAY_OF_MONTH)); } public void readData(DataInput in) throws IOException { name = DataIO.readFixedString(NAME_SIZE, in); salary = in.readDouble(); int y = in.readInt(); int m = in.readInt(); int d = in.readInt(); GregorianCalendar calendar = new GregorianCalendar(y, m - 1, d); hireDay = calendar.getTime(); } public static final int NAME_SIZE = 40; public static final int RECORD_SIZE = 2 * NAME_SIZE + 8 + 4 + 4 + 4; private String name; private double salary; private Date hireDay; } class DataIO { public static String readFixedString(int size, DataInput in) throws IOException { StringBuilder b = new StringBuilder(size); int i = 0; boolean more = true; while (more && i < size) { char ch = in.readChar(); i++; if (ch == 0) { more = false; } else { b.append(ch); } } in.skipBytes(2 * (size - i)); return b.toString(); } public static void writeFixedString(String s, int size, DataOutput out) throws IOException { for (int i = 0; i < size; i++) { char ch = 0; if (i < s.length()) { ch = s.charAt(i); } out.writeChar(ch); } } }