一、流的概念
- 在计算机中,流是个抽象的概念,是对输入输出设备的抽象。在Java程序中,对于数据的输入输出操作,都以“流”的方式进行
- 流具有方向性,可以分为输入和输出。
- 以java程序本身作为参照点,如果数据是从程序“流向”文件,那么这个流就是输出流,如果数据是从文件“流向”程序,那么这个流就是输入流。例如:
注意,这里是以文件进行举例,java程序中还可以把数据写入到网络中、内存中等
二、流的分类
根据数据的流向分为:输入流和输出流
- 输入流:把数据从其他设备上读到程序中的流
- 输出流:把数据从程序中写出到其他设备上的流
根据数据的类型分为:字节流和字符流
- 字节流:以字节为单位(byte),读写数据的流
- 字符流:以字符为单位(char),读写数据的流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流 | 字节输出流 |
字符流 | 字符输入流 | 字符输出流 |
- 字节输入流,在程序中,以字节的方式,将设备(文件、内存、网络等)中的数据读进来
- 字节输出流,在程序中,以字节的方式,将数据写入到设备(文件、内存、网络等)中
- 字符输入流,在程序中,以字符的方式,将设备(文件、内存、网络等)中的数据读进来
- 字符输出流,在程序中,以字符的方式,将数据写入到设备(文件、内存、网络等)中
三、流的结构
几乎所有的流,都是派生自四个抽象的父类型:
- InputStream ,代表字节输入流类型
- OutputStream ,代表字节输出流类型
- Reader ,代表字符输入流类型
- Writer ,代表字符输出流类型
Java中常用的流及其关系结构,如下:
注意,一般情况下,一个流,会具备最起码的三个特点:
- 是输入还是输出
- 是字节还是字符
- 流的目的地
其中,流的目的地指定是: 如果是输入流,就表示这个流从什么地方读数据,如果是输出流,就表示这个流把数据写到什么地方!
例如, InputStream ,是所有字节输入流的抽象父类型。那么它的子类型一定是以 字节 的方式,从某个地方把数据 读 取到程序中,只是不同的子类型,它们的目的地 不一样,并且一般可以通过子类型的名字看出它的的目的地是哪里,例如:
- ByteArrayInputStream ,它是以字节的形式,去读取某个地方的数据,通过名字可以看出,它
的目的地是字节数组中,也就是以字节的形式从byte数组中读取数据 - FileInputStream ,它是以字节的形式,去读取某个地方的数据,通过名字可以看出,它的目的
地是文件,也就是以字节的形式从文件中读取数据
四、字节流
概述
计算机中,存储一切数据(文本、图片、视频等),都是以二进制的形式进行的,最终都是一个一个的字节,所以使用流,进行传输数据的时候,也是一个一个的字节进行的。
- java.io.InputStream是所有字节输入流的抽象父类型:
- java.io.OutputStream是所有字节输出流的抽象父类:
在代码中,使用流操作数据的基本步骤是:
- 声明流
- 创建流
- 使用流
- 关闭流
控制台
使用字节流,从控制台读取数据,以及向控制台中写数据。
例如:
public class Demo {
public static void main(String[] args) {
//1声明流
InputStream in = null;
OutputStream out = null;
//2创建流
in = System.in;
out = System.out;
//3使用流,,这里使用System中已经创建好的流对象
try {
int data = -1;
data = in.read();
out.write(data);
data = in.read();
out.write(data);
out.flush();//刷新缓冲区,强制所有数据写出去
} catch (IOException e) {
e.printStackTrace();
}finally {
//4关闭流
if(in!=null) {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(out!=null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}}
结果如下
这里是一次读取用一个字节,然后把字节值输出
注意,这个子类中重写的read方法,会让线程阻塞,等待用户在控制台中的输入,用户输入并按下回车,程序中的read方法就从阻塞状态恢复过来,从而读取到用户输入的内容。
也可以一次读取多个字节,然后将本次读取到
的都输出,加入while循环可以让程序一直读取和写出
public class Demo2 {
public static void main(String[] args) {
//1声明流
InputStream in = null;
OutputStream out = null;
//2创建流
in = System.in;
out = System.out;
//3使用流
try {
byte[] buf = new byte[10];
int len = -1;
//循环,一个流不停的读数据,一个流不同的写数据
while((len=in.read(buf))!=-1) {
System.out.println(len+":"+Arrays.toString(buf));
out.write(buf,0,len);//本次读了多几个字节,那么就写出几个字节
}
len = in.read(buf);
out.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4关闭流
if(in!=null) {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(out!=null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}}