Java学习从菜鸟变大鸟之二 输入输出流(IO)

来源:互联网 发布:为什么何炅是Gay知乎 编辑:程序博客网 时间:2024/05/01 09:49

 http://blog.csdn.net/lishehe/article/details/18941199

 

在软件开发中,数据流和数据库操作占据了一个很重要的位置,所以,熟悉操作数据流和数据库,对于每一个开发者来说都是很重要的,今天就来总结一下JavaI/O.


  流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样。


    Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。而类 InputStreamReader 和 OutputStreamWriter 处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。

     

结构图看一下整个数据流中的API结构和对象继承关系信息:



    Java中的流分为两种,一种是字节流,另一种是字符流,字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的:


实例分析

( 一 )以字节为导向的 stream------InputStream/OutputStream


InputStream 和 OutputStream 是两个 abstact 类,对于字节为导向的 stream 都扩展这两个鸡肋(基类)




    在这其中InputStream和OutputStream在早期的Java版本中就已经存在了,它们是基于字节流的,而基于字符流的Reader和Writer是后来加入作为补充的。以上的层次图是Java类库中的一个基本的层次体系。

  

    在这四个抽象类中,InputStream和Reader定义了完全相同的接口:


[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family: SimSun; font-size: 18px;">int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) </span>  


    而OutputStream和Writer也是如此:


[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family: SimSun; font-size: 18px;">int write(int c)  int write(char cbuf[])  int write(char cbuf[], int offset, int length)</span>  



这六个方法都是最基本的,read()和write()通过方法的重载来读写一个字节,或者一个字节数组。


2、 OutputSteam





( 二 )以字符为导向的 stream Reader/Writer

以 Unicode 字符为导向的 stream ,表示以 Unicode 字符为单位从 stream 中读取或往 stream 中写入信息。

Reader/Writer 为 abstact 类

以 Unicode 字符为导向的 stream 包括下面几种类型:


1. Reader




总结


字节流和字符流的区别:


1,字节流读取的时候,读到一个字节就返回一个字节。字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。

2,字节流可以处理所有类型数据,如图片,mp3,avi。而字符流只能处理字符数据。

结论:只要是处理纯文本数据,就要优先考虑使用字符流。除此之外都用字节流



Reader中的常见的方法:

1,int read():读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.

2,int read(char[]):将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1.

3,close():读取字符其实用的是window系统的功能,就希望使用完毕后,进行资源的释放



Writer中的常见的方法:

1,write(ch): 将一个字符写入到流中。

2,write(char[]): 将一个字符数组写入到流中。

3,write(String): 将一个字符串写入到流中。

4,flush():刷新流,将流中的数据刷新到目的地中,流还存在。

5,close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。、



FileWriter:该类没有特有的方法只有自己的构造函数。该类特点在于

1,用于处理文本文件。

2,该类中有默认的编码表,

3,该类中有临时缓冲。

构造函数:在写入流对象初始化时,必须要有一个存储数据的目的地。

对于读取或者写入流对象的构造函数,以及读写方法,还有刷新关闭功能都会抛出IOException或其子类。所以都要进行处理。或者throws抛出,或者try catch处理



细节:

当指定绝对路径时,定义目录分隔符有两种方式:

1,反斜线但是一定要写两个。\\new FileWriter("c:\\demo.txt");

2,斜线/  写一个即可。new FileWriter("c:/demo.txt");


字符流的缓冲区:缓冲区的出现提高了对流的操作效率。

原理:其实就是将数组进行封装。

对应的对象:

BufferedWriter:特有方法:newLine():跨平台的换行符。

BufferedReader:特有方法:readLine():一次读一行,到行标记时,将行标记之前的字符数据作为字符串返回。当读到末尾时,返回null。

在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,

所以在建立缓冲区对象时,要先有流对象存在。

其实缓冲内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储。为了提高操作数据的效率。

readLine():方法的原理:

其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法。只不过,每一次读到一个字符,先不进行具体操作,先进行临时存储。当读取到回车标记时,将临时容器中存储的数据一次性返回。

既然明确了原理,我们也可以实现一个类似功能的方法。


[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <span style="font-family: SimSun; font-size: 18px;">import java.io.*;  
  2. public class TestBufferStream2 {  
  3.   public static void main(String[] args) {  
  4.     try {  
  5.       BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\share\\java\\dat2.txt"));  
  6.       BufferedReader br = new BufferedReader(  
  7.              new FileReader("d:\\share\\java\\dat2.txt"));  
  8.       String s = null;  
  9.       for(int i=1;i<=100;i++){  
  10.         s = String.valueOf(Math.random());  
  11.         bw.write(s);  
  12.         bw.newLine();  
  13.       }  
  14.       bw.flush();  
  15.       while((s=br.readLine())!=null){  
  16.         System.out.println(s);  
  17.       }  
  18.       bw.close();   
  19.       br.close();  
  20.     } catch (IOException e) { e.printStackTrace();}  
  21.   }  
  22. }</span>  

操作数组的流对象。

1,操作字节数组

ByteArrayInputStream

ByteArrayOutputStream

toByteArray();

toString();

writeTo(OutputStream);

2,操作字符数组。

CharArrayReader

CharArrayWriter

对于这些流,源是内存。目的也是内存。

而且这些流并未调用系统资源。使用的就是内存中的数组。

所以这些在使用的时候不需要close。

操作数组的读取流在构造时,必须要明确一个数据源。所以要传入相对应的数组。

对于操作数组的写入流,在构造函数可以使用空参数。因为它内置了一个可变长度数组作为缓冲区。

0 0