一、
JAVA
流式输入
/
输出原理
在
Java
程序中,对于数据的输入
/
输出操作以
“
流
”
(
Stream
)方式进行;
J2SDK
提供了各种各样的
“
流
”
类,用以获取不同种类的数据:程序中通过标准的方法输入或输出数据。
二、输入输出流分类
Java.io
包中定义了多个流类型(类或抽象类)来实现输入
/
输出功能;可以从不同的角度对其进行分类:
按数据流的方向不同可以分为输入流和输出流
按照处理数据单位不同可以分为字节流和字符流
按照功能不同可以分为节点流和处理流
我们来理解两个概念:
字节流:最原始的一个流,读出来的数据就是
010101
这种最底层的数据表示形式,只不过它是按
照字节来读的,一个字节(
Byte
)是
8
位(
bit
)读的时候不是一个位一个位的来读,而是一个字节
一个字节来读。
字符流:字符流是一个字符一个字符地往外读取数据。一个字符是
2
个字节
J2SDK
所提供的所有流类型位于包
Java.io
内,都分别继承自以下四种抽象流类型。
输入流:
InputStream
(字节流),
Reader
(字符流)
输出流:
OutPutStream
(字节流),
Writer
(字符流)
什么叫输入流?什么叫输出流?
用一根管道一端插进文件里,一端插进程序里面,然后开始读数据,那么这是输入还是输出呢?
如果站在文件的角度上,这叫输出。
如果站在程序的角度上,这叫输入。
记住,以后说输入流和输出流都是站在程序的角度上来说
三、节点流和处理流
3.1.
节点流类型
节点流就是一根管道直接插到数据源上面,直接读数据源里面的数据,或者是直接往数据源里面写入数据。典型的节点流是文件流:文件的字节输入流(FileInputStream
),文件的字节输出流
(
FileOutputStream
),文件的字符输入流(
FileReader
),文件的字符输出流(
FileWriter
)。
3.2.
处理流类型
处理流是包在别的流上面的流,相当于是包到别的管道上面的管道。
四、
InputStream(
输入流
)
继承自
InputStream
的流都是用于向程序中输入数据,且数据的单位为字节(
8bit
);下图中深色为节点流,浅色为处理流。
4.1.InputStream的基本方法
//读取一个字节并以整数的形式返回(0~255)
//如果返回-1就说明已经到了输入流的末尾
int read() throws IOException
//读取一系列字节并存储到一个数组buffer
//返回实际读取的字节数,如果读取前已到输入流的末尾,则返回-1
int read(byte[] buffer) throws IOException
//读取length个字节
//并存储到一个字节数组buffer,从length位置开始
//返回实际读取的字节数,如果读取前以到输入流的末尾返回-1.
int read(byte[] buffer,int offset,int length) throws IOException
//关闭流释放内存资源
void close() throws IOException
//跳过n个字节不读,返回实际跳过的字节数
long skip(long n) throws IOException
read()
方法是一个字节一个字节地往外读,每读取一个字节,就处理一个字节。
read(byte[] buffffer)
方法读取数据时,先把读取到的数据填满这个byte[]
类型的数组
buffffer(buffffer
是内存里面的一块缓冲区
)
,然后再处理数组里面的数据。这就跟我们取水一样,先用一个桶去接,等桶接满水后再处理桶里面的水。如果是每读取一个字节就处理一个字节,这样子读取也太累了。
4.2
案例
try {
in = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 记录读取到的字符数
long num = 0;
// 创建一个字节
byte[] bytes = new byte[1024];
// 调用read 可能发生异常 所以需要捕获 !=-1
try {
*//* while ((b = in.read()) != -1) {
System.out.println((char) b);
num++;
}*//*
// 传入数组接收
while ((b = in.read(bytes))!= -1) {
System.out.println(bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
// 打印多少个字符
System.out.println(num);
FileOutputStream out = null;
try {
out = new FileOutputStream(path,true);
// 写入数组 // 如果在调用FileOutputStream的构造方法时没有加入true,
out.write(bytes);
}
catch (Exception e) {
e.printStackTrace();
}
五、
OutputStream(
输出流
)
5.1.OutputStream
的基本方法
//向输出流中写入一个字节数据,该字节数据为参数b的低8位
void write(int b) throws IOException
//将一个字节类型的数组中的数据写入输出流
void write(byte[] b) throws IOException
//将一个字节类型的数组中的从指定位置(off)开始的len个字节写入到输出流
void write(byte[] b,int off,int len) throws IOException
//关闭流释放内存资源
void close() throws IOException
//将输出流中缓冲的数据全部写出到目的地
void flush() throws IOException
六、
Reader
流
Reader
: 和
InputStream
一模一样,唯一的区别就在于读的数据单位不同
继承自
Reader
的流都是用于向程序中输入数据,且数据的单位为字符(
16bit
)
七、
Writer
流
八、处理流讲解
8.1.
第一种处理流
——
缓冲流
(Buffffering)
缓冲流要
”
套接
“
在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法。J2SDK
提供了四种缓冲流,常用构造方法如下:
BufferedReader(Reader in)
BufferedReader(Reader in,int sz) //sz 为自定义缓冲区的大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
BufferedOutputStream(InputStream in)
BufferedOutputStream(InputStream in,int size)
缓冲输入流支持其父类的
mark
和
reset
方法。
BufffferedReader
提供了
readLine
方法用于读取一行字符串
BufffferedWriter
提供了
newLine
用于写入一个行分隔符
对于输出的缓冲流,写出的数据会现在内存中缓存,使用
flflush
方法将会使内存中的数据立刻写出
带有缓冲区的,缓冲区
(Buffffer)
就是内存里面的一小块区域,读写数据时都是先把数据放到这块缓冲区 域里面,减少io
对硬盘的访问次数,保护我们的硬盘。可以把缓冲区想象成一个小桶,把要读写的数据想象成水,每次读取数据或者是写入数据之前,都是先把数据装到这个桶里面,装满了以后再做处理。
这就是所谓的缓冲。先把数据放置到缓冲区上,等到缓冲区满了以后,再一次把缓冲区里面的数据写入到硬盘上或者读取出来,这样可以有效地减少对硬盘的访问次数,有利于保护我们的硬盘。
8.2.
第二种处理流
——
转换流
InputStreamReader
和
OutputStreamWriter
用于字节数据到字符数据之间的转换
InputStreamReader
需要和
InputStream “
套接
”
。
OutputStreamWriter
需要和
OutputStream “
套接
”
。
转换流在构造时可以指定其编码集合
转换流非常的有用,它可以把一个字节流转换成一个字符流,转换流有两种,一种叫
InputStreamReader
,另一种叫
OutputStreamWriter
。
InputStream
是字节流,
Reader
是字符流,
InputStreamReader
就是把
InputStream
转换成
Reader
。
OutputStream
是字节流,
Writer
是字符流,
OutputStreamWriter
就是把
OutputStream
转换成
Writer
。把
OutputStream
转换成
Writer
之后就可以
一个字符一个字符地通过管道写入数据了,而且还可以写入字符串。我们如果用一个
FileOutputStream流往文件里面写东西,得要一个字节一个字节地写进去,但是如果我们在FileOutputStream
流上面套上 一个字符转换流,那我们就可以一个字符串一个字符串地写进去。
8.5.
对象流
——Object
直接将
Object
写入或读出
transient
关键字
transient
:透明的,用它来修饰的成员变量在序列化的时候不予考虑,也就是当成不存在。
serializable
接口
externaliazble
接口
ObjectInputStream objectInputStream = new ObjectInputStream(in);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
/*
* 凡是要将一个类的对象序列化成一个字节流就必须实现Serializable接口
* Serializable接口中没有定义方法,Serializable接口是一个标记性接口,用来给类作标记,
只是起到一个标记作用。
* 这个标记是给编译器看的,编译器看到这个标记之后就可以知道这个类可以被序列化 如果想把某个
类的对象序列化,就必须得实现Serializable接口
*/
class T implements Serializable {
// Serializable的意思是可以被序列化的
int i = 10;
int j = 9;
double d = 2.3;
int k = 15;
// transient int k = 15;
// 在声明变量时如果加上transient关键字,那么这个变量就会被当作是透明的,即不存在。
}
九、
IO
流总结