首先什么是流:流(Stream)的概念来源于UNIX中的管道(pipe)概念,在unix中,管道是一条不间断的字节流,用来实现程序和进程间的通信,或者读写外围设备、外部文件等。流,必须有源端和目的端,可以是文件,内存或者网络等。流的创建是为了更方便的处理数据的输入输出。
其次,对于输入流输出流如何区分,相信有很多人闹不清楚,本人也是很长时间弄不太明白,简单的来说,输入输出均是相对于内存来说,这样就比较好理解了,简单的来说:输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。
第三,类别,流可以分为字节流和字符流。字节流为原始数据,需要用户读入后进行相应的编码转换,而字符流的实现是居于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成字符。字节流由inputStream和outputStream处理(注意,这个类均是抽象类,实现的是他们的子类),为了让数据处理的更方便,java在后期版本中加上了字符流的Reader和Writer类。
程序可以从中连续读取字节的对象叫输入流,用InputStream类完成,程序能向其中连续写入字节的对象叫输出流,用OutputStream类完成。InputStream与OutputStream对象是两个抽象类,还不能表明具体对应哪种IO设备。它们下面有许多子类,包括网络,管道,内存,文件等具体的IO设备,如FileInputStream类对应的就是文件输入流,是一个节点流类,我们将这些节点流类所对应的IO源和目标称为流节点(Node)。
InputStream定义了Java的输入流模型。该类中的所有方法在遇到错误的时候都会引发IOException异常,下面是InputStream类中方法的一个简要说明:
InputStream是一个抽象类,程序中实际使用的是它的各种子类对象。不是所有的子类都会支持InputStream中定义的某些方法的,如skip,mark,reset等,这些方法只对某些子类有用。
注意点:
一个对象在没有引用变量指向它时会变成垃圾,最终会被垃圾回收器从内存中清除。对于我们创建的流对象,干嘛还要“调用close方法将它关闭,以释放与其相关的资源”呢?这相关的资源到底是些什么呢?我们在程序中创建的对象都是对应现实世界中有形或无形的事物,计算机操作系统所产生的东西当然也是现实世界中的事物,也就是说,程序中的对象也可以对应计算机操作系统所产生的一个其他东西,专业地说,这些东西叫资源,流就是操作系统产生的一种资源。当我们在程序中创建了一个IO流对象,同时系统内也会创建了一个叫流的东西,在这种情况下,计算机内存中实际上产生了两个事物,一个是Java程序中的类的实例对象,一个是系统本身产生的某种资源,我们以后讲到的窗口,Socket等都是这样的情况。Java垃圾回收器只能管理程序中的类的实例对象,没法去管理系统产生的资源,所以程序需要调用close方法,去通知系统释放其自身产生的资源。
OutputStream是一个定义了输出流的抽象类,这个类中的所有方法均返回void,并在遇到错误时引发IOException异常。下面是OutputStream的方法:
下面是从网上找到的它们的结构图:
Java中的字符是unicode编码,是双字节的,而InputStream与OutputStream是用来处理字节的,在处理字符文本时不太方便,需要编写额外的程序代码。Java为字符文本的输入输出专门提供了一套单独的类,Reader、Writer两个抽象类与InputStream、OutputStream两个类相对应,同样,Reader、Writer下面也有许多子类,对具体IO设备进行字符输入输出,如FileReader就是用来读取文件流中的字符。
对于Reader和Writer,我们就不过多的说明了,大体的功能和InputStream、OutputStream两个类相同,但并不是它们的代替者,只是在处理字符串时简化了我们的编程。简单例子:
前面我们讲过,Java支持字节流和字符流,我们有时需要字节流和字符流之间的转换。
InputStreamReader 和OutputStreamWriter
这两个类是字节流和字符流之间转换的类,InputStreamReader可以将一个字节流中的字节解码成字符,OuputStreamWriter将写入的字符编码成字节后写入一个字节流。其中InputStreamReader有两个主要的构造函数:
为了达到最好的效率,避免频繁的字符与字节间的相互转换,我们最好不要直接使用这两个类来进行读写,应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader。例如:
- BufferedWriter out=new BufferedWriter(newOutputStreamWriter(System.out));
- BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
我们接着从一个更实际的应用中来熟悉InputStreamReader的作用,怎样用一种简单的方式一下就读取到键盘上输入的一整行字符?只要用下面的两行程序代码就可以解决这个问题:
- BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
- String strLine = in.readLine();