IO流主要是用来解决数据传输问题。
数据以二进制的形式在程序和设备之间流动传输,把这种数据传输的方式称之为输入流、输出流。
流的分类
根据数据的流向分为:输入流和输出流
- 输入流:把数据从其他设备上读取到程序中的流
- 输出流:把数据从程序中写出到其它设备上的流
根据数据的类型分为:字节流和字符流
- 字节流:以字节为单位(byte),读写数据的流
- 字符流:以字符为单位(char),读写数据的流
几乎所有的流都是派生自四个抽象的父类型
- InputStream(字节输入流)
- OutputStream(字节输出流)
- Reader(字符输入流)
- Writer(字符输出流)
使用流操作数据的基本步骤:
- 声明流。
- 创建流。
- 使用流。
- 关闭流。
输入流中提供read方法读取数据,输出流中提供write方法写出数据。
字节流:
常见字节输入流(InputStream)
ByteArrayInputStream:字节数组输入流,用于从字节数组中读取数据。
FileInputStream:文件输入流,用于从文件中读取数据。
ObjectInputStream:对象输入流,从某个地方读取出对象的字节序列,并产生对应的对象。
PipedInputStream:管道输入流,从管道中读取数据,一般需创建线程读取数据。
DataInputStream:数据输入流,把读取到的若干个字节,转化为指定类型的数据。
BufferedInputStream:字节缓冲流,用于给字节输入流提供缓冲功能,提高读取数据效率。
InputStream中最核心的三个read方法:
//每次读取一个字节,返回值是本次读取的字节值
public abstract int read() throws IOException;
//每次都多个字节,并存放在指定字节数组中,返回值是本次一共读取了多少个字节(字节数)
public int read(byte b[]) throws IOException{
return read(b,0,b.length);
}
//每次读取多个字节,并存放到指定的字节数组中,返回值是本次一共读取了多少个字节(字节数)
//同时可以指定从什么位置开始存放,以及在数组中最多存放多少个字节
public int read(byte b[],int off,int len) throws IOException{
//.......
}
常见字节输出流(OutputStream):
ByteArrayOutputStream:字节数组输出流,把数据写入到字节数组中。
FileOutputStream:文件输出流,把数据写入到文件中。
ObjectOutputStream:对象输出流,将对象转换为字节序列。
PipedOutputStream:管道输出流,将数据写入到管道中,创建线程写出数据。
DataOutputStream:数据输出流,把指定类型的数据,转化为字节并写出去。
BufferedOutputStream:字节缓冲流,用于给字节输出流提供缓冲功能,提高写入数据效率。
管道流需将管道进行对接,才能进行操作。
OutputStream中最核心的三个write方法:
//写出去一个字节值
public abstract void write(int b) throws IOException;
//把一个字节数组中的值全部写出去
public void write(byte b[]) throws IOException{
write(b,0,b.length);
}
//写出字节数组,指定开始位置,以及写出的字节数量
public void write(byte b[],int off,int len) throws IOException{
//.......
}
字符流:
常见的字符输入流(Reader):
BufferedReader:字符缓冲流,给字符输入流提供缓冲功能。
CharArrayReader:字符数组流,从字符数组中读取数据。
InputStreamReader:转换流,将字节输入流转换为字节输入流,并指定编码。
PipedReader:管道字符输入流,实现多线程之间的管道通信。
Reader中最核心的三个read方法:
//每次读取一个字符,返回这个字符的编码值
public int read() throws IOException{
//...
};
//每次读取多个字符,并存放到指定字符数组中,返回值是本次读取到的字符个数
public int read(char ch[]) throws IOException{
return read(ch,0,ch.length);
}
//每次读取多个字符,并存放到指定的字符数组中,返回值是本次一共读取到的字符个数
//同时可以指定从什么位置开始存放,以及在数组中最多存放多少个字符
public int read(char ch[],int off,int len) throws IOException{
//.......
}
常见的字符输出流(Writer):
BufferedWriter:字符缓冲流,给字符输出流提供缓冲功能。
CharArrayWriter:字符数组流,把数据写入字符数组中。
InputStreamWriter:转换流,将字节输出流转换为字节输出流,并指定编码。
PipedWriter:管道字符输出流,实现多线程之间的管道通信,将数据写入到管道中。
Writer中最核心的三个write方法:
//写出去一个字符,注意字符可以使用int值来表示
public abstract void write(int c) throws IOException{
//.....
}
//写出去数组中多个字符
public void write(char ch[]) throws IOException{
write(ch,0,ch.length);
}
//写出去数组中的多个字符
//可以指定从数组的什么位置开始写,以及多少个字符
abstract public void write(char ch[],int off,int len) throws IOException;
//写出去一个字符串
public void write(String str) throws IOException{
write(str,0,str.length());
}
//写出去一个字符串
//可以指定从字符串的什么位置开始写,以及多少个字符
public void write(String str,int off,int len){
//.....
}
对象流(字节流):
对象输入流:ObjectInputStream
对象输出流:ObjectOutputStream
程序运行过程中,除了字符串之外,任何对象想要传输数据都必须序列化。
将对象序列化:创建对象的类实现java.io.Serializable接口。
序列化:
程序中,可以用一个字节序列来表示对象,该字节序列包含了对象的类型、对象中的数据等。如果这个字节序列写出到文件中,就相当于在文件中持久保存了这个对象的信息。
反序列化:
从文件中将这个字节序列读取回来,在内存中重新生成这个对象,对象的类型,对象中的数据等,都和之前的那个对象保持一致。(内存地址不同)
transient:关键字transient可以修饰类中的属性,它是让对象在进行序列化的时候,忽略掉指定的属性。
转换流(字符流)
输入:InputStreamReader
输出:OutputStreamWrite
转换流可以在把一个字节流转换为字符的同时,指定转换的字符编码。
在数据传输过程中读写数据的编码要保持一致。