io详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhanghongjie0302/article/details/51288017

一、什么是流

       首先什么是流:流(Stream)的概念来源于UNIX中的管道(pipe)概念,在unix中,管道是一条不间断的字节流,用来实现程序和进程间的通信,或者读写外围设备、外部文件等。流,必须有源端和目的端,可以是文件,内存或者网络等。流的创建是为了更方便的处理数据的输入输出。

       其次,对于输入流输出流如何区分,相信有很多人闹不清楚,本人也是很长时间弄不太明白,简单的来说,输入输出均是相对于内存来说,这样就比较好理解了,简单的来说:输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。

        第三,类别,流可以分为字节流和字符流。字节流为原始数据,需要用户读入后进行相应的编码转换,而字符流的实现是居于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成字符。字节流由inputStream和outputStream处理(注意,这个类均是抽象类,实现的是他们的子类),为了让数据处理的更方便,java在后期版本中加上了字符流的Reader和Writer类。


二、字节流:InputStream和OutputStream

        程序可以从中连续读取字节的对象叫输入流,用InputStream类完成,程序能向其中连续写入字节的对象叫输出流,用OutputStream类完成。InputStream与OutputStream对象是两个抽象类,还不能表明具体对应哪种IO设备。它们下面有许多子类,包括网络,管道,内存,文件等具体的IO设备,如FileInputStream类对应的就是文件输入流,是一个节点流类,我们将这些节点流类所对应的IO源和目标称为流节点(Node)。

        

        InputStream定义了Java的输入流模型。该类中的所有方法在遇到错误的时候都会引发IOException异常,下面是InputStream类中方法的一个简要说明:

     

[plain] view plain copy
  1. int read()返回下一个输入字节的整型表示,,如果返回-1表示遇到流的末尾,结束。  
  2.       int read(byte[]b)读入b.length个字节放到b中并返回实际读入的字节数。  
  3.      int read(byte[]b,int off,int len) 这个方法表示把流中的数据读到,数组b中,第off个开始的len个数组元素中.  
  4.      long skip(long n) 跳过输入流上的n个字节并返回实际跳过的字节数。  
  5.       int availabale() 返回当前输入流中可读的字节数。  
  6.      void mark(int readlimit)在输入流的当前位置处放上一个标志,允许最多再读入readlimit个字节。  
  7.         void reset() 把输入指针返回到以前所做的标志处。  
  8.       boolean markSupported() 如果当前流支持mark/reset操作就返回true。  
  9.      void close()  在操作完一个流后要使用此方法将其关闭,系统就会释放与这个流相关的资源。  

InputStream是一个抽象类,程序中实际使用的是它的各种子类对象。不是所有的子类都会支持InputStream中定义的某些方法的,如skip,mark,reset等,这些方法只对某些子类有用。

        注意点:

        一个对象在没有引用变量指向它时会变成垃圾,最终会被垃圾回收器从内存中清除。对于我们创建的流对象,干嘛还要“调用close方法将它关闭,以释放与其相关的资源”呢?这相关的资源到底是些什么呢?我们在程序中创建的对象都是对应现实世界中有形或无形的事物,计算机操作系统所产生的东西当然也是现实世界中的事物,也就是说,程序中的对象也可以对应计算机操作系统所产生的一个其他东西,专业地说,这些东西叫资源,流就是操作系统产生的一种资源。当我们在程序中创建了一个IO流对象,同时系统内也会创建了一个叫流的东西,在这种情况下,计算机内存中实际上产生了两个事物,一个是Java程序中的类的实例对象,一个是系统本身产生的某种资源,我们以后讲到的窗口,Socket等都是这样的情况。Java垃圾回收器只能管理程序中的类的实例对象,没法去管理系统产生的资源,所以程序需要调用close方法,去通知系统释放其自身产生的资源。


          OutputStream是一个定义了输出流的抽象类,这个类中的所有方法均返回void,并在遇到错误时引发IOException异常。下面是OutputStream的方法:

        

[plain] view plain copy
  1. void write(int b) 将一个字节写到输出流。注意,这里的参数是int型,它允许write使用表达式而不用强制转换成byte型。  
  2.         void write(byte[] b) 将整个字节数组写到输出流中。  
  3.         void write(byte [] b,int off,int len) 将字节数组b中的从off开始的len个字节写到输出流。  
  4.         void flush彻底完成输出并清空缓冲区。  
  5.         void close关闭输出流。  

       下面是从网上找到的它们的结构图:




三、字符流Reader和write

       

        Java中的字符是unicode编码,是双字节的,而InputStream与OutputStream是用来处理字节的,在处理字符文本时不太方便,需要编写额外的程序代码。Java为字符文本的输入输出专门提供了一套单独的类,Reader、Writer两个抽象类与InputStream、OutputStream两个类相对应,同样,Reader、Writer下面也有许多子类,对具体IO设备进行字符输入输出,如FileReader就是用来读取文件流中的字符。

对于Reader和Writer,我们就不过多的说明了,大体的功能和InputStream、OutputStream两个类相同,但并不是它们的代替者,只是在处理字符串时简化了我们的编程。

       简单例子:

       

[java] view plain copy
  1. import java.io.*;  
  2. public class FileStream  
  3. {  
  4.     public static void main(String[] args)  
  5.     {  
  6.         File f = new File("hello.txt");   
  7.         try  
  8.         {  
  9.             FileWriter out = new FileWriter(f);  
  10.             out.write("www.it315.org");  
  11.             out.close();  
  12.         }  
  13.         catch(Exception e)  
  14.         {  
  15.             System.out.println(e.getMessage());  
  16.         }  
  17.           
  18.         try  
  19.         {  
  20.             FileReader in = new FileReader(f);  
  21.             char [] buf = new char[1024];  
  22.             int len = in.read(buf);  
  23.             System.out.println(new String(buf,0,len));  
  24.         }  
  25.         catch(Exception e)  
  26.         {  
  27.             System.out.println(e.getMessage());  
  28.         }  
  29.     }  
  30. }  

四、字节流与字符流的转换

前面我们讲过,Java支持字节流和字符流,我们有时需要字节流和字符流之间的转换。

InputStreamReader 和OutputStreamWriter

这两个类是字节流和字符流之间转换的类,InputStreamReader可以将一个字节流中的字节解码成字符,OuputStreamWriter将写入的字符编码成字节后写入一个字节流。其中InputStreamReader有两个主要的构造函数:

[plain] view plain copy
  1. InputStreamReader(InputStream in) //用默认字符集创建一个InputStreamReader对象  
  2. InputStreamReader(InputStreamin,String CharsetName) //接受以指定字符集名的字符串,并用//该字符集创建对象  
  3. OutputStreamWriter也有对应的两个主要的构造函数:  
  4. OutputStreamWriter(OutputStream in) //用默认字符集创建一个OutputStreamWriter对象  
  5. OutputStreamWriter(OutputStream in,StringCharsetName) //接受以指定字符集名的字符串,  
  6. //并用该字符集创建OutputStreamWriter对象  

为了达到最好的效率,避免频繁的字符与字节间的相互转换,我们最好不要直接使用这两个类来进行读写,应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader。例如:

  1. BufferedWriter out=new BufferedWriter(newOutputStreamWriter(System.out));  
  2. BufferedReader in=new BufferedReader(new InputStreamReader(System.in));  

我们接着从一个更实际的应用中来熟悉InputStreamReader的作用,怎样用一种简单的方式一下就读取到键盘上输入的一整行字符?只要用下面的两行程序代码就可以解决这个问题:

  1. BufferedReader in=new BufferedReader(new InputStreamReader(System.in));  
  2. String strLine = in.readLine();  
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页