import java.io.*;import java.time.LocalDate;public class Test { public static void main(String[] args){ RandomAccessTest.test(); }}/* 2.3 读写二进制数据 *//* 2.3.2 随机访问文件 写了大半天,突然发现这个实验好像不是太严谨: 1.RandomAccessFile算长度时,应该是根据字节数算出来的 2.写字符串时,我们只是指定了码元数量,我们写的是固定码元数量的字符串 3.这样的化,我们记录的Employee.RECORD_SIZE根本就代表不了一条记录的长度 4.但是我们最后又通过RandomAccessFile的长度和Employee.RECORD_SIZE来计算记录数量 5.我觉得这个实验有问题,以后研究吧 */class Employee { private String name; private double salary; private LocalDate hireDay; public static final int NAME_SIZE = 30; public static final int RECORD_SIZE = 50; public Employee(String name, double salary, LocalDate hireDay) { this.name = name; this.salary = salary; this.hireDay = hireDay; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public LocalDate getHireDay() { return hireDay; } public void setHireDay(LocalDate hireDay) { this.hireDay = hireDay; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", salary=" + salary + ", hireDay=" + hireDay + '}'; }}class DataIO { //Java核心技术 卷二 第十版 2.3.2节 //写出从字符串开头开始的指定数量的码元,如果码元过少,该方法会用‘0’来补齐字符串 public static void writeFixedString(String s, int size, DataOutput output) throws IOException { for (int i = 0; i < size; i++) { char ch =0; if(i<s.length()) ch = s.charAt(i); output.write(ch); } } //Java核心技术 卷二 第十版 2.3.2节 //从输入流中读入字符,直至读入size个码元,或者直至遇到具有0值的字符串,然后跳出输入字段中剩余的0值。 public static String readFixedString1(int size, DataInput in) throws IOException { StringBuilder sb = new StringBuilder(); for (int i = 0; i < size; i++) { char c; if ((c = in.readChar()) != 0) { sb.append(c); } } return sb.toString(); } //功能和上一个方法是一样的,但是这个效率会高那么一点点 public static String readFixedString2(int size, DataInput in) throws IOException { StringBuilder sb = new StringBuilder(); /* int i; for (i = 0; i < size; i++) { char c; if ((c = in.readChar()) == 0) { break; } sb.append(c); } in.skipBytes(2*(size-i)); //这个地方不是太严谨 */ //用书中代码测试一下 int i =0; boolean more = true; while (more && i < size) { char ch = in.readChar(); i++; if (ch == 0) { more = false; } else { sb.append(ch); } } in.skipBytes(2 * (size - i)); return sb.toString(); }}class RandomAccessTest { public static void test() { Employee[] staff = new Employee[]{ new Employee("A", 10, LocalDate.now()), new Employee("B", 20, LocalDate.now()), new Employee("C", 30, LocalDate.now()) }; //写入 try(DataOutputStream out = new DataOutputStream(new FileOutputStream("employee1.dat"))) { for (Employee e : staff) { writeData(out, e); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //读取 try(RandomAccessFile in = new RandomAccessFile("employee1.dat","r")) { int n = (int) (in.length() / Employee.RECORD_SIZE); Employee[] newStaff = new Employee[n]; for (int i = n - 1; i >= 0; i--) { in.seek(i*Employee.RECORD_SIZE); newStaff[i] = readDate(in); } for (Employee e : newStaff) { System.out.println(e); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static void writeData(DataOutput out, Employee employee) throws IOException { DataIO.writeFixedString(employee.getName(), Employee.NAME_SIZE, out); out.writeDouble(employee.getSalary()); LocalDate hireDay = employee.getHireDay(); out.writeInt(hireDay.getYear()); out.writeInt(hireDay.getMonthValue()); out.writeInt(hireDay.getDayOfMonth()); } private static Employee readDate(DataInput input) throws IOException { String name = DataIO.readFixedString2(Employee.NAME_SIZE, input); double salary = input.readDouble(); int y= input.readInt(), m= input.readInt(), d= input.readInt(); return new Employee(name, salary, LocalDate.of(y, m, d)); }}/* 2.3.3 ZIP文档 ZipFile API: ZipFile(String name) ZipFile(File file) Enumeration entries() ZipEntry getEntry(String name) InputStream getInputStream(ZipEntry ze) String getName() 从这个类的API中可以看出来,还有一种使用Zip的方案。先通过ZipFile对象,得到 这个压缩包中的每一条记录,然后再指定某条具体的记录,得到其中的数据。 */
《Java核心技术卷二》笔记