JAVA I/O(五)

IO流:BufferedReader
BufferedReader:
  1. 这是一个缓冲流,它有一个方法:readLine()
  2. 如果要使用这个流则必须是纯文本的文件
  3. 它不是一个节点流,是一个包装流所以在创建它的对象的时候需要先创建一个Reader系列的节点流再使用它进行包装
实例代码如下:
public void testReadLine() throws IOException {
    //创建IO流
    BufferedReader br = new BufferedReader(new FileReader("resources/test.txt"));
    //IO流操作
    String line;
    //按行进行读取
    while((line = br.readLine()) != null){
        System.out.println(line);
    }
    //关闭IO流
    br.close();
}
 
数据IO流
DataOutputStream
    数据的输出流,允许应用程序以适当的方式把 基本Java数据类型写入输出流中,然后,在需要时应用程序可以使用数据输入流(DataInputStream)把数据读入。
DataInputStream
    数据的输入流,允许应用程序以与机器无关的方式从底层输入流中 读取基本Java数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
注意:
    1.Java基本数据类型:8种,而基本Java数据类型:8种 + String
    2.数据IO流不是节点流,需要包装一个节点流
DataOutputStream实例代码:
public void save() throws IOException {
    //有如下数据需要进行保存,保存完的数所需要可以进行恢复
    String name = "张三";
    int age = 30;
    char gender = 'M';
    double sal = 5500.0;
 
 
    //创建IO流
    DataOutputStream dos = new DataOutputStream(new FileOutputStream("resources/data.dat"));
 
 
    //IO流操作
    dos.writeUTF(name);
    dos.writeInt(age);
    dos.writeChar(gender);
    dos.writeDouble(sal);
 
 
    //关闭IO流
    dos.close();
}
DataInputStream实例代码:
public void resume() throws IOException {
    //创建IO流
    DataInputStream dis = new DataInputStream(new FileInputStream("resources/data.dat"));
 
 
    //IO流操作
    String name = dis.readUTF();
    int age = dis.readInt();
    char gender = dis.readChar();
    double sal = dis.readDouble();
 
 
    System.out.println("name = " + name);
    System.out.println("age = " + age);
    System.out.println("gender = " + gender);
    System.out.println("sal = " + sal);
 
 
    //关闭IO流
    dis.close();
}
注意:在使用DataInputStream进行读操作时需要保证与写的顺序要一致
 
对象IO流:ObjectInpuStream、ObjectOutputStream
前面说所的数据IO流它只能处理基本java类型,如果要处理一个对象则需要使用对象IO流
对象IO流有两个:
ObjectOutputStream:输出对象,序列化(对象-->字节)
ObjectInputStream:读取对象,反序列化(字节-->对象)
如:有下面这个类的对象
public class Student implements Serializable {
    private int id;
    private String name;
    private String address;
 
 
    public Student(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }
 
 
    public Student() {
    }
 
 
    public int getId() {
        return id;
    }
 
 
    public void setId(int id) {
        this.id = id;
    }
 
 
    public String getName() {
        return name;
    }
 
 
    public void setName(String name) {
        this.name = name;
    }
 
 
    public String getAddress() {
        return address;
    }
 
 
    public void setAddress(String address) {
        this.address = address;
    }
}
接下来 我们创建一个Student类型的对象并把对象的信息写到指定的文件当中进行序列化
public void save() throws IOException {
    Student student = new Student(1,"张三","学府路8888号");
    //创建IO流对象
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("resources/student.dat"));
    //IO流操作
    oos.writeObject(student);
    //关闭IO流
    oos.close();
}
注意:在使用ObjectOuptStream写入对象的信息到文件的时候一定要求对象所属的类需要implements Serializable,表示这个类的对象是可序列化的。
java.io.Serializable接口:它是一个标识型接口,没有抽象方法等,只需要在声明类的时候写上implements Serializable即可
当我们写入到文件中后,我们要把这个对象读取出来则可以如下:
public void Read() throws IOException, ClassNotFoundException {
    //创建IO流对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("resources/student.dat"));
    //IO流操作
    Student student = (Student)ois.readObject();
    System.out.println(student.getName() + ":" + student.getAddress());
    //关闭IO流
    ois.close();
}
注意:在对象的序列化与反序列化之间要有一个serialVersionUID这个需要关注,因为在序列化对象的信息后,在反序列回来前又可能类的信息被修改了
这个时候反序列化回来的时候会报错
我们一般在实现Serializable接口时,加上一个serialVersionUID(序列化版本ID)
如果我们的类上没有加上这个,则只要类重新编译过后,原来序列化的数据就无法反序列化(当没有手动上上序列化版本ID的情况下,每次编译都会自动随机产生一个序列货版本的值)
当我们加上了这个序列化版本ID,只要这个值不变,原来序列化的数据依然可以反序列化
 
当我们对象中某些属性是不希望去序列化的,这个时候如何操作?
我们可以在类中对指定的不需要序列化的属性加上 transient 标识,它表示临时的瞬时的
 
注意:一个类中的静态变量是不会被序列化的
 
序列化接口:Externalizable
java.io.Externalizable
这个接口的原码写法如下:
public interface Externalizable extends java.io.Serializable {
    void writeExternal(ObjectOutput out) throws IOException;
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
注意:这个接口与Serializable不同之处是,它是有两个抽象方法的
writeExternal:这个方法用来确定哪些成员变量需要序列化,以及序列化的顺序
readExternal:这个方法用来确定如何进行反序列化
当使用了Externalizable去实现了序列化及反序列化的操作后,对象中的static属性、transient属性都可以进行序列化及反序列化
如下代码:
1.声明一个类
public class Student2 implements Externalizable{
private static String school;
private int id;
private String name;
private transient int age;
 
public Student2(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
 
public Student2() {
}
 
public static String getSchool() {
return school;
}
 
public static void setSchool(String school) {
Student2.school = school;
}
 
public int getId() {
return id;
}
 
public void setId(int id) {
this.id = id;
}
 
public String getName() {
return name;
}
 
public void setName(String name) {
this.name = name;
}
 
public int getAge() {
return age;
}
 
public void setAge(int age) {
this.age = age;
}
 
 
 
@Override
public String toString() {
return id + "," + name + "," + age + "," + school;
}
 
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(school);
out.writeInt(id);
out.writeUTF(name);
out.writeInt(age);
}
 
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
school = in.readUTF();
id = in.readInt();
name = in.readUTF();
age = in.readInt();
}
}
 
2.对以上的类进行序列化与反序列化
public class Testio13{
@Test
public void save() throws IOException {
Student2 student2 = new Student2(1,"张三",23);
student2.setSchool("清华大学");
 
//创建IO
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("resources/student2.dat"));
//IO操作
oos.writeObject(student2);
//关闭IO
oos.close();
}
 
@Test
public void read() throws IOException, ClassNotFoundException {
//创建IO
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("resources/student2.dat"));
//IO操作
Student2 stu2 = (Student2)ois.readObject();
System.out.println(stu2);
}
}
 
 
System中IO流对象:System.in、System.out
System.in  ----> InputStream
System.out ----> PrintStream
 
PrintStream:它是包装输出流,提供打印的表示形式。
    1.它是不会抛出IOException异常的
    2.它会自动刷新
如果其他IO流,可以手动刷新,使用flush()
System.in、System.out等对象在System类中是public static final的常量,并且被初始化为null,那这些对象的值在什么时候进行的赋值呢?
注意:在类中有一个静态代码块
private static native void registerNatives();
static{
    registerNatives();
}
这里在初始化的时候是使用c语言来实现的
上面说这些对象都是静态的常量,但是它们还是会有setIn(),setOut()等方法,其设置值的过程也是调用了非JAVA的代码来实现的
那么我们可以使用set方法来控制输出的位置,比如我们控制其输出到指定的文件(System.out默认是控制台)
public void test01() throws FileNotFoundException {
    System.setOut(new PrintStream(new FileOutputStream("resources/print.txt")));
    System.out.println("你好");
    System.out.println("中国");
    System.out.println("hello world");
}
对于System.in的操作也是一样
public void test02() throws FileNotFoundException {
    System.setIn(new FileInputStream("resources/print.txt"));
    Scanner scanner = new Scanner(System.in);
    System.out.println(scanner.nextLine());
    System.out.println(scanner.nextLine());
    System.out.println(scanner.nextLine());
    scanner.close();
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值