其他流
一、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窗口上輸入要獲取的位置即可,超出位置會拋異常。