1. Java输入输出流的概述:
输入输出概述:
输入:是一个外界进入到程序的方向,通常我们需要“读取”外界的数据时,使用输入;
输出:是一个程序发送到外界的方向,通常我们需要“写出”数据到外界时,使用输出。
输入输出流分类:
整体上分为字节型输入输出和字符型输入输出。两者的区别:
字节型的输入输出:针对的是byte数组,字节型的输入输出的父类分别是InputStream和OutStream
字符型的输入输出:针对的是char数组或者String,字符型的输入输出的父类分别是Reader和Writer。
常用输入输出流所在包:
java.io
常用输入输出流图谱:
2 常用字节流
字节型输入输出的父类:
1)输入:
InputStream是所有字节输入流的父类,是抽象类,不能给你直接用自身的构造函数初始化。常用的方法如下:
Int read:读取一个字节,以int形式返回,该int值的“低8为”有效,若返回-1则表示EOF。
Int read:尝试最多读取给定数组的length个字节并缓存入该数组,返回值为实际读取到的字节量。
2)输出:
OnputStream是所有字节输出流的父类,是抽象类,不能给你直接用自身的构造函数初始化。常用的方法如下:
void write:输出一个字节,写的是给定的int的”低8位”。
void write:将给定的字节数组中的所有字节全部写出。
文件流的输入和输出:
1)文件输出流:
FileOutputStream是文件的字节输出流使用该流可以以字节为单位将数据写入文件。构造方法如下:
FileOutputStream:创建一个指向File对象表示的文件中写出数据的文件流。
FileOutputStream:创建一个向具有指定名称的文件中写出数据的文件输出流。
补充:若指定的文件已经包含内容,那么当使用以上构造函数对文件写入数据时,会将该文件中原有数据全部清除。
2)文件输出流:
追加模式的文件输出流的构造方法
FileOutputStream:创建一个指向File对象表示的文件中写出数据的文件流。
FileOutputStream: 创建一个向具有指定名称的文件中写出数据的文件输出流。
补充:以上两个方法中,第二个参数为true时,通过该构造函数写出的数据都是在文件末尾追加的。
3)文件输入流:
FileInputStream是文件的字节输入流,以字节为单位从文件中读取。构造方法:
FileInputStream:创建一个指向File对象表示的文件中读取数据的文件输入流。
FileInputStream:创建用于读取给定的文件系统中的路径名所指定的文件的文件输入流。
4)read和write方法及代码实例:
read:从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。此方法是FileInputStream继承自InputStream的方法。
write:将指定的字节写入此输出流。此方法是FileOutputStream继承自OutputStream的方法。
文件流的代码实例:
批量读写:read和write方法:
int read:从此输入流中最多b.length个字节的数据读入到字节数组b中,如果到文件末尾或者无可用字节了,则返回-1;此方法是FileInputStream继承自InputStream的方法。
void write:将b.length个字节从指定byte数组写入此文件输出流中。此方法是FileOutputStream继承自OutputStream的方法。
void write:将指定byte数组中从偏移量off开始的len个字节写入此文件输出流。此方法是FileOutputStream继承自OutputStream的方法。
批量读写:read和write的代码实例:
缓冲流的输入和输出:
1)缓冲输出流BufferedOutputStream的原理:
BufferedOutputStream缓冲输出流内部维护一个缓冲区,每当我们向该流写数据时,都会将数据存入缓冲区,当缓冲区已满时,缓冲流会将数据一次性全部写出。
构造函数是:BufferedOutputStream
2)缓冲输出流BufferedOutputStream的flush方法:
有时我们需要在执行完某些写出操作后,就希望将这些数据实时写出,而非在缓冲区中保存直到缓冲区满后才写出。这时我们可以使用缓冲流的一个方法flush。
void flush:清空缓冲区,将缓冲区中的数据强制写出
3)缓冲输入流BufferedItputStream的原理:
BufferedInputStream是缓冲字节输入流。其内部维护着一个缓冲区,使用该流在读取一个字节时,该流会尽可能多的一次性读取若干字节并存入缓冲区,然后逐一的将字节返回,直到缓冲区中的数据全部读取完毕,会再次读取若干字节从而反复。这样就减少了读取的次数。
构造函数是:BufferedInputStream
4)实现基于缓冲区的文件复制的代码实例:
补充:其中的read和write方法使用的是继承自父类的相关方法,具体方法描述可参考”字节型输入输出的父类”
对象流的输入和输出:
1)序列化和反序列化的概念:
对象是存在于内存中的。如果需要将对象保存到硬盘上,这时,需要将对象转化为一个字节序列,而这个过程就称为对象序列化。
相反,如果将一个字节序列转换为对应的对象,这个过程就称为反序列化。
2)ObjectOutputStream实现对象序列化的输出流:
ObjectOutputStream是用来对对象进行序列化的输出流。常用构造函数和方法如下:
ObjectOutputStream
void writeObject:该方法可以将给定的对象转换为一个字节序列后写出
3)ObjectItputStream实现对象反序列化的输入流:
ObjectInputStream是用来对对象进行序列化的输出流。常用构造函数和方法如下:
ObjectInputStream
void readObject:该方法可以从流中读取字节并转换为对应的对象。
4)Serializable接口:
作用:
在对对象进行序列化时有一个要求,就是需要序列化的对象所属的类必须实现Serializable接口
应用此接口的注意事项:
实现该接口不需要重写任何方法。做为做为可序列化的标志。
通常实现该接口的类需要提供一个常量serialVersionUID,表明该类的版本。
若不显示声明,再对象序列化时也会根据当前类的各个方面,计算该类的默认serialVersionUID,但是不同平台编译期实现有所不同,所以若想跨平台,都应该显示声明版本号。
serialVersionUID常量的好处:如果对象序列化到硬盘上后,更改了类的属性。那么反序列化时,就会出现InvalidClassException,这样就会造成不兼容的问题。
但当使用了serialVersionUID,判断出该值相同时,它就会将不一样的field以Type的预设值反序列化,可避开不兼容性问题
5) transient关键字:
对象在序列化后得到的字节序列往往比较大,有时我们在对一个对象进行序列化时可以忽略某些不必要的属性,从而对序列化后得到的自己序列“瘦身”。可用关键字transient
被该关键字修饰的属性在序列化时其值将被忽略。
对象流的代码实例:
基础对象代码:
//序列化一个对象,输出到文件中:
//反序列化一个对象,从文件中读取出来: