其他流
一、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窗口上输入要获取的位置即可,超出位置会抛异常。
来源:https://www.cnblogs.com/wzy330782/p/5475789.html