其他流
一、ObjectInputStream/ObjectOutputStream
① ObjectInputStream和ObjectOutputStream分別與FileInputStream和FileOutputStream一起使用時,可以對應用程序提供對對象的持久存儲。我們把對象以某種特定的編碼格式寫入稱之為“序列化”。把寫入的編碼格式內容還原成對象稱之為“反序列化”。
② 被序列化的對象必須實現Serializable接口。
序列化示例:
1 //必須實現Serializable接口
2 class Student implements Serializable{
3 private String name;
4 private int age;
5 public Student(String name, int age) {
6 super();
7 this.name = name;
8 this.age = age;
9 }
10 public String getName() {
11 return name;
12 }
13 public void setName(String name) {
14 this.name = name;
15 }
16 public int getAge() {
17 return age;
18 }
19 public void setAge(int age) {
20 this.age = age;
21 }
22 @Override
23 public String toString() {
24 return "Student [name=" + name + ", age=" + age + "]";
25 }
26
27 }
主方法:
1 Student stu=new Student("zhangsan", 30);
2 FileOutputStream fos=new FileOutputStream("d:/test.txt");
3 ObjectOutputStream oos=new ObjectOutputStream(fos);
4 oos.writeObject(stu);//把對象序列化到指定的文件輸出流中
5 oos.close();//釋放資源
反序列化:
主方法:
1 ObjectInputStream ois=new ObjectInputStream(new FileInputStream("d:/test.txt"));
2 try {
3 Student stu2= (Student)ois.readObject();
4 System.out.println(stu2);
5 } catch (ClassNotFoundException e) {
6 e.printStackTrace();
7 }
8 ois.close();
反序列化成功之後,再在Student中添加一個地址屬性。
private String address;
發現不能反序列化了,因為序列化的對象與反序列化的對象不一致。
解決辦法:Eclipse的Student類行號左邊有一個小燈,


添加一個版本號。再次進行序列化操作,新增屬性後反序列化也能成功,它會自動取出序列化中不存在的屬性。
二、InputStreamReader/OutputStreamWriter
①轉換流是指將字節流與字符流之間的轉換。
②轉換流的出現方便了對文本的讀寫,她在字符流與字節流之間架起了一座橋梁,使原本毫無關聯的兩種流操作能進行轉化,提高了程序的靈活性。
③ 節流中的數據都是字符時,轉成字符流操作更高效。
④ 如果使用非默認編碼保存文件或讀取文件時,需要用到轉換流。因為字節流的重載構造方法中有指定編碼格式的參數,而FileReader與FileWriter是默認編碼的文本文件。
⑤ 常見的編碼表
a) ASCII:美國標准信息交換碼。用一個字節的7位可以表示。
b) ISO8859-1:拉丁碼表。歐洲碼。表用一個字節的8位表示。
c) GB2312:中國的中文編碼表。
d) GBK:中國的中文編碼表升級,融合了更多的中文文字符號。
e) Unicode:國際標准碼,融合了多種文字。所有文字都用兩個字節來表示,Java語言使用的就是Unicode。
f) UTF-8:最多用三個字節來表示一個字符。
g) ……
將內容以指定編碼的格式存入文件:
1 OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("d:/code.txt"), "utf-8");
2 BufferedWriter bw=new BufferedWriter(osw);
3 bw.write("你好");
4 bw.close();
讀取文件:
1 BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("d:/code.txt"), "utf-8"));
2 String line=null;
3 while((line=br.readLine())!=null){
4 System.out.println(line);
5 }
6 br.close();
三、RandomAccessFile 隨機訪問文件
①支持對隨機訪問文件的讀取和寫入。
②隨機訪問文件的行為類似存儲在文件系統中的一個大型byte數組。存在指向該隱含數組的光標或索引,稱為文件指針。
③ 入操作從文件指針開始讀取字節,隨著對字節的讀取而前移此文件指針。
④ 如果隨機訪問文件以讀取/寫入模式創建,則輸出操作也可用;輸出操作從文件指針開始寫入字節,隨著對字節的寫入而前移此文件指針。
⑤ 寫入隱含數組末尾之後的輸入操作導致該數組擴展。
⑥ 該文件指針可用通過getFilePointer方法讀取,通過seek方法設置。
案例說明:創建一個Person類,內有name屬性占15個字符,即30個字節,age屬性4個字節,共34個字節。將多個Person對象放入RandomAccessFile中。然後在指定的位置上取出Person對象(名字,年齡)。
創建一個Person類
1 class Person {
2 private String name;
3 private int age;
4
5 public Person() {
6
7 }
8
9 public Person(String name, int age) {
10 StringBuilder builder = null;
11 if (name != null) {
12 builder = new StringBuilder(name);
13 } else {
14 builder = new StringBuilder(15);
15 }
16 builder.setLength(15);// 固定長度為15個字符,不滿15時,'\u0000'
17 this.name = builder.toString();
18 this.age = age;
19 }
20
21 public String getName() {
22 return name;
23 }
24
25 public void setName(String name) {
26 StringBuilder builder = null;
27 if (name != null) {
28 builder = new StringBuilder(name);
29 } else {
30 builder = new StringBuilder(15);
31 }
32 builder.setLength(15);// 固定長度為15個字符,不滿15時,'\u0000'
33 this.name = builder.toString();
34 }
35
36 public int getAge() {
37 return age;
38 }
39
40 public void setAge(int age) {
41 this.age = age;
42 }
43
44 // 每個對象所占的字節數
45 public static int size() {
46 return 34;
47 }
48
49 }
讀取名字時不用將全部字節都讀取出來,所以應該替換空字節。方法如下,將其寫在與主方法同一個類下即可
1 private static String readName(RandomAccessFile randomaccessFile)
2 throws IOException {
3 char[] name = new char[15];
4 for (int i = 0; i < name.length; i++) {
5 name[i] = randomaccessFile.readChar();
6 }
7 return new String(name).replace('\u0000', ' ');
8 }
主方法:
1 Person[] persons = { new Person("zhangsan", 10),
2 new Person("lisi", 24), new Person("wangwu", 36),
3 new Person("zhaoliu", 66) };
4 RandomAccessFile randomaccessFile = new RandomAccessFile(
5 "d:/test2.txt", "rw");
6 // 寫入數據到RandomAccessFile這個對象中、
7 for (int i = 0; i < persons.length; i++) {
8 randomaccessFile.writeChars(persons[i].getName());
9 randomaccessFile.writeInt(persons[i].getAge());
10 }
11 // 讀取指定位置上的Person對象
12 Scanner scanner = new Scanner(System.in);
13 System.out.println("讀取第幾個Person對象數據");
14 int num = scanner.nextInt();
15 // 使用seek方法來操作存取位置
16 randomaccessFile.seek((num - 1) * Person.size());
17 Person person = new Person();
18 person.setName(readName(randomaccessFile));
19 person.setAge(randomaccessFile.readInt());
20 System.out.println("姓名:" + person.getName());
21 System.out.println("年齡:" + person.getAge());
22 randomaccessFile.close();
運行後在Console窗口上輸入要獲取的位置即可,超出位置會拋異常。