IO流:(Input,Output)
我们在做项目时,除了自定义的一些数据外,还可能需要从"外界"引入数据,或者将数据导出到"外界"。这时,我们需要I/O操作。
外界:指的可能是 键盘,显示器,硬盘,另外一个程序。
输入:又叫读入操作 数据从"外界"流向程序
输出:又叫写出操作 数据从程序流向"外界"
流: 就是数据序列, 一经创建成功,就会打开一个通道。所以使用完应该进行关闭操作。
流的概念和作用
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流的分类:
(1)按照流向分类:
输入流
输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
(2)按照处理的数据单位分类:
字节流(8位的字节)
字符流(16位的字节)
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
(3)按照功能分类:
节点流:直接连接两个设备的流类型
处理流:对节点流再次封装与处理的流类型
字节流:
抽象父类 InputStream/OutputStream
InputStream:定义了字节输入流的常用方法
int available()
void close()
int read():读取一个字节,存入int的低八位上,范围是0-255
int read(byte[] b):读取字节存入字节数组b中,返回的是读取的有效字节个数。
int read(byte[] b,int off,int len)
skip(int n)
OutputStream:定义了字节输出流的常用方法
void close()
void flush():冲刷,作用是将流的数据,冲刷进文件中
void write(int b):写一个字节
void write(byte[] b):写一个字节数组
void write(byte[] b,int off,int len)
文件字节流:FileInputStream/FileOutputStream
文件字节输入流:FiIeInputStream
(1)构造器:
FileInputStream(File file)
创建一个指定路径的File对象的文件输入流对象
FileInputStream(String name)
创建一个指定路径的字符串的文件输入流对象
(2)常用方法:
int read()
读取该流中的一个字节数据,即8位二进制,存储到一个int数
据的低八位上
如果返回-1,读至文件末尾,
long skip(long n)
跳过流中n个字节
int read(byte[] b)
读取字节存入byte数组中,最多能读b.length个字节
返回的是实际读取的字节个数
int available()
查看此输入流中剩余的字节数量
文件字节输出流:FileOutputStream
(1)构造器:
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
创建一个指定路径的输出流对象,append表示在文件末尾追加
PS:如果指定路径下的文件名不存在,会自动创建。
如果父路径不存在,则报异常FileNotFoundException
(2)常用方法:
void write(int b)
写出参数b中的一个字节,int类型的低八位。
void write(byte[] b)
将字节数组b中的字节按顺序写出
void write(byte[] b,int off,int len)
将字节数组b中的字节按顺序写出,从下标off,写len个
字节缓冲流:BufferedInputStream/BufferedOutputStream
字节缓冲输入流:BufferedInputStream
在读取字节时,也是一个字节一个字节的读,次数多,效率低。
使用缓冲输入流,内部维护了一个缓冲区,默认8k,先一次性将缓冲区装满等待读取.
当将缓冲区的数据读完,缓冲区再次存储后续数据。读取的次数明显降低效率高
(1)构造器:
BufferedInputStream(InputStream is);
BufferedInputStream(InputStream is,int size);
(2)常用方法:
int read(byte[] bs)
读取缓冲区里的字节存储bs中,
当一次性得去的字节小于缓冲区,我们是从缓冲区里读数据。
此时,效率高
当一次性读取的字节超出缓冲区大小。
不使用缓冲区,直接从文件里读。
int read(byte[] bs,int off,int len)
字节缓冲输出流:BufferedOutputStream
在写数据时,如果一个字节一个字节的写,写的次数明显很多,效率就会变得很低。
如何提高效率呢。
缓冲输出流的特点是:在流里维护了一个缓冲区,写字节时,先将字节
写入缓冲区, 当缓冲区满时,再一次性的将数据写到文件里。这样就
降低了写的次数,因此提高了效率。
因此缓冲输出流缺失即时性,可以使用flush方法进行冲刷
(1)常用构造器:
BufferedOutputStream(OutputStream out)
创建一个指定字节输出流的缓冲流对象
BufferedOutputStream(OutputStream out,int size)
创建一个指定字节输出流的缓冲流对象,并设置缓冲区的大小
PS:当一次写的字节超出缓冲区大小,会出现溢出情况,溢出的字节会先写出到文件中
(2)常用方法:
void write(int b):写int数据的低八位,写入缓冲区内
void write(byte[] b,int off,int len):写指定长度len的字节数组,写入缓冲区
数据字节流,与缓冲流一样,父类都是过滤字节流(FilterOutputStream/FilterInputStream)
这两个类提供了几个特殊的方法,可以直接写基本数据类型
字节数据流:DataInputStream/DataOutputStream
字节数据输入流:DataInputStream
字节数据输出流:DataOutputStream
(1)构造器:
DataOutputStream(OutputStream os):创建一个指定字节输出流的数据输出流对象
(2)常用方法:
除了提供写一个字节和写一个字节数组的方法外,还提供了如下方法
writeByte(int b)
writeShort(int s)
writeInt(int i)
writeLong(long l)
writeFloat(float f)
writeDouble(double d)
writeChar(int c)
writeBoolean(boolean b)
writeUTF(String s)
字节对象流:ObjectIntputStream /ObjectOutputStream
有的时候,我们可能需要将内存中的对象持久化到硬盘上,或者将
硬盘中的对象信息读到内存中,这个时候我们需要使用对象输入输出流。
序列化:是对象转换成一个字节序列的过程,是一个写操作
反序列化: 一个字节序列转换成对象的过程 ,是一个读操作
字节对象输入流:ObjectIntputStream
(1)构造器:
ObjectIntputStream(OutputStream out)
创建一个指定字节输入流的对象输入流对象。
(2)常用方法:
除了提供了一些基本数据类型的读方法外,还提供了
Object readObject():从硬盘上读取一个字节序列,转换成对象
字节对象输出流:ObjectOutputStream
(1)构造器:
ObjectOutputStream(OutputStream out)
创建一个指定字节输出流的对象输出流对象。
(2)常用方法:
除了提供了一些基本数据类型的写方法外,还提供了
void writeObject(Object obj):将内存中的对象持久化到硬盘上
Serializable:序列化接口
如果想将对象序列化,那么对象的类型必须实现此接口。此接口内什么都没有,只是一个序列化标识。
serialVersionUID:
每个能序列化的对象,在被序列化时,系统会默认给此对象的类计算一个
序列化版本号。不同的平台默认提供的序列化版本号多数情况下不会相同。
因此当我们反序列时,如果硬盘里存储的对象的版本号与当前设计的类型
的版本号不一致。会出现运行时异常:
java.io.InvalidClassException,这种情况叫不兼容问题。
如果我们想解决不兼容问题。我们应该手动提供版本号。尽可能的相同
这样来解决不兼容问题
另外一种情况:
序列化过后,可能会修改类型,如果使用系统默认提供的
版本号,在反序列时,会有异常,如果手动提供,不出现异常
多出来的成员变量,以默认值的形式,赋值给反序列化回来的对象。
transient:成员变量的一个修饰词,可以理解为瘦身。
有的时候,在序列化对象时,我们不需要将对象的某些成员变量
值持久化到硬盘上(因为不重要),此时,我们可以在这些成员变量
添加修饰词transient(保存时,进行减肥)
字符流:
抽象父类:Writer/Reader
在输出输入操作时,以字符为单位进行操作,默认是unicode编码集字符流的抽象父类分别是Writer/Reader
Reader提供了字符输入流的常用方法
int read():读一个字符,存储到int的低16位
int read(char[] cbuf):将数据读进字符数组中,返回的是读取的有效字符个数
int read(char[] cbuf, int off, int len) :将字符读入数组的一部分
Writer提供了字符输出流的常用方法
void close():关闭
void write(char[] cbuf):写一个字符数组
void write(char[] cbuf, int off, int len):写一个字符数组的一部分
write(int c):写一个字符
write(String str):写一串字符
write(String str, int off, int len) :写字符串的一部分
字符转换流:InputStreamReader/OutputStreamReader
字符转换输入流:InputStreamReader
将字节转换成字符读进程序中
(1)构造器:
InputStreamReader(InputStream in)
创建一个使用默认字符集的InputStreamReader。
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, CharsetDecoder dec)
InputStreamReader(InputStream in, String charsetName)
创建一个使用指定字符集的InputStreamReader。
字符转换输出流:OutputStreamWriter
将字符转换成字节写出到硬盘上
(1)构造器:
OutputStreamWriter(OutputStream out)
创建一个指定字节输出流的字符输出流对象,采用的是系统默认的编码集
OutputStreamWriter(OutputStream out, Charset cs)
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
OutputStreamWriter(OutputStream out, String charsetName)
创建一个指定字节输出流的字符输出流对象,采用指定编码集。
(2)常用方法:
write(int a);
当a的低16位,如果被设计成相应的字符时,如果两个字节都是
有效字节,会写出两个。如果低16位对应是无效字符,或是有效
字节只有一位时,会写一个字节。
字符缓冲流:BufferedReader/PrintWriter
字符缓冲输入流:BufferedReader:
提供了一个缓冲区
(1)构造器:
BufferedReader(Reader in) :创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz): 创建使用指定大小的输入缓冲区的缓冲字符输入流。
(2)常用方法:
String readLine():
读一行字符串,读至换行符号为止,返回的数据不包含换行符
当返回值为null时,表示读至文件末尾
字符缓冲输出流:PrintWriter
提供了丰富的方法,比BufferedWriter更加常用,此类型提供了行自动刷新的功能
(1)构造器:
PrintWriter(File file)
PrintWriter(OutputStream out)
PrintWriter(OutputStream out, boolean autoFlush)
PrintWriter(String fileName)
PrintWriter(Writer out)
PrintWriter(Writer out, boolean autoFlush)
上述构造器,有第二个参数的,可以设置为true,表示行自动刷新。
只有一个参数的构造器,相当有两个参数时,设置为false的情况,即取消了行自动刷新的功能
(2)常用方法:
println() 通过写入行分隔符字符串来终止当前行。
println(boolean x) 打印一个布尔值,然后终止该行。
void println(char x) 打印一个字符,然后终止该行。
void println(char[] x) 打印字符数组,然后终止行。
void println(double x) 打印双精度浮点数,然后终止行。
void println(float x) 打印一个浮点数,然后终止该行。
void println(int x) 打印一个整数,然后终止该行。
void println(long x) 打印一个长整型,然后终止行。
void println(Object x) 打印一个对象,然后终止该行。
void println(String x)
文件字符流:FileWriter/FileReader
文件字符输入流:FileReader
相当于InputStreamReader和FileInputStream合起来的功能内部也维护了一个缓冲区
(1)构造器:
FileReader(File file)
FileReader(String fileName)
常用方法与InputStreamReader的方法差不多
文件字符输出流:FileWriter:
相当于OutputStreamWriter与FileOutputStream合起来的功能,内部也维护了一个缓冲区,但是需要手动flush
(1)构造器:
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
append:表示追加,但是此流不能设置字符集。
常用方法与 OutputStreamWriter的差不多