Java IO 流的总结

   

目录

流的概念和作用

IO流的分类

字符流和字节流

输入流和输出流

1) 输入流

2) 输出流

3)特性

节点流

处理流

转换流

Java IO流对象

1.输入字节流InputStream

2.输出字节流OutputStream

3.字符输入流Reader

4.字符输出流Writer

5.字节流的输入与输出的对应

6.字符流的输入与输出的对应

7.字节流和字符流的区别(重点)

8.非流式文件类--File类

9.RandomAccessFile类

10、System类对IO的支持

参考的文章:


一直在工作中使用,但是从学习之后,就没有总结过。最近java IO流使用的比较频繁,因为无论是socket通信还是文件的操作都涉及到了IO流的操作。

网上的抬头都是一张图,其实我觉得很好,看懂了这个图基本上就懂了IO流。借用网上别人的图(感谢别人的总结):

流的概念和作用

流是一组有顺序的,有起点和终点的字节集合,是对数据的传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类。方便更直观的进行数据操作。

IO流的分类

  • 根据处理数据类型的不同分为:字符流和字节流
  • 根据数据流向不同分为:输入流和输出流
  • 按数据来源(去向)分类:
  •          1、File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter 
             2、byte[]:ByteArrayInputStream, ByteArrayOutputStream 
             3、Char[]: CharArrayReader,CharArrayWriter 
             4、String:StringBufferInputStream, StringReader, StringWriter 
             5、网络数据流:InputStream,OutputStream, Reader, Writer

字符流和字节流

  • 字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:

    读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

    处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

    字节流:一次读入或读出是8位二进制。

    字符流:一次读入或读出是16位二进制。

  •  

    字符流的由来:

  •  Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

    设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据,所以字节流一样可以处理字符数据。

     

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

输入流和输出流

根据数据的输入、输出方向的不同对而将流分为输入流和输出流。

1) 输入流

     程序从输入流读取数据源。数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道

 

    

输入字节流 InputStream
InputStream 是所有的输入字节流的父类,它是一个抽象类。

  • 来看看几种不同的InputStream:

  • ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
    PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
    ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

  • FileInputStream把一个文件作为InputStream,实现对文件的读取操作
  • ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
  • StringBufferInputStream:把一个String对象作为InputStream
  • PipedInputStream:实现了pipe的概念,主要在线程中使用
  • SequenceInputStream:把多个InputStream合并为一个InputStream

2) 输出流

   程序向输出流写入数据。将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。

    

        输出字节流 OutputStream
OutputStream 是所有的输出字节流的父类,它是一个抽象类

OutputStream提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。

ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
PipedOutputStream 是向与其它线程共用的管道中写入数据。
ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。

几种不同的OutputStream:

  1. ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
  2. FileOutputStream:把信息存入文件中
  3. PipedOutputStream:实现了pipe的概念,主要在线程中使用
  4. SequenceOutputStream:把多个OutStream合并为一个OutStream

Reader和InputStream类似;Writer和OutputStream类似。

有两个需要注意的:

  1. InputStreamReader : 从输入流读取字节,在将它们转换成字符。
  2. BufferReader :接受Reader对象作为参数,并对其添加字符缓冲器,使用readline()方法可以读取一行。
  • 3)特性

    采用数据流的目的就是使得输出输入独立于设备。

    输入流( Input  Stream )不关心数据源来自何种设备(键盘,文件,网络)。InputStream或者Reader:从文件中读到程序中;

    输出流( Output Stream )不关心数据的目的是何种设备(键盘,文件,网络)。输出流:OutputStream或者Writer:从程序中输出到文件中;

    相对于程序来说,输出流是往存储介质或数据通道写入数据,而输入流是从存储介质或数据通道中读取数据,一般来说关于流的特性有下面几点:

  • 1、先进先出,最先写入输出流的数据最先被输入流读取到。

    2、顺序存取,可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机访问中间的数据。(RandomAccessFile可以从文件的任意位置进行存取(输入输出)操作

    3、只读或只写,每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要分别提供两个流。 

    节点流

  • 节点流:直接与数据源相连,读入或读出。
    直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。


    常用的节点流
    父 类 :InputStream 、OutputStream、 Reader、 Writer
    文 件 :FileInputStream 、 FileOutputStrean 、FileReader 、FileWriter 文件进行处理的节点流
    数 组 :ByteArrayInputStream、 ByteArrayOutputStream、 CharArrayReader 、CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
    字符串 :StringReader、 StringWriter 对字符串进行处理的节点流
    管 道 :PipedInputStream 、PipedOutputStream 、PipedReader 、PipedWriter 对管道进行处理的节点流

  • 处理流

  • 处理流和节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。


    常用的处理流
    缓冲流:BufferedInputStrean 、BufferedOutputStream、 BufferedReader、 BufferedWriter 增加缓冲功能,避免频繁读写硬盘。
    转换流:InputStreamReader 、OutputStreamReader实现字节流和字符流之间的转换。
    数据流: DataInputStream 、DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来。

  • 转换流

InputStreamReader 、OutputStreamWriter 要InputStream或OutputStream作为参数,实现从字节流到字符流的转换。

构造函数

InputStreamReader(InputStream);        //通过构造函数初始化,使用的是本系统默认的编码表GBK。
InputStreamReader(InputStream,String charSet);   //通过该构造函数初始化,可以指定编码表。
OutputStreamWriter(OutputStream);      //通过该构造函数初始化,使用的是本系统默认的编码表GBK。
OutputStreamwriter(OutputStream,String charSet);   //通过该构造函数初始化,可以指定编码表。

Java IO流对象

1.输入字节流InputStream

IO 中输入字节流的继承图可见上图,可以看出:

1.    InputStream是所有的输入字节流的父类,它是一个抽象类。

2.    ByteArrayInputStream、StringBufferInputStream(上图的StreamBufferInputStream)、FileInputStream是三种基本的介质流,它们分别从Byte数组、StringBuffer、和本地文件中读取数据。

3.    PipedInputStream是从与其它线程共用的管道中读取数据.

4.    ObjectInputStream和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。

InputStream中的三个基本的读方法
      abstract int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
      intread(byte[]?b) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
      intread(byte[]?b, int?off, int?len) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。

流结束的判断:方法read()的返回值为-1时;readLine()的返回值为null时。


其它方法
      long skip(long?n):在输入流中跳过n个字节,并返回实际跳过的字节数。
      int available() :返回在不发生阻塞的情况下,可读取的字节数。
      void close() :关闭输入流,释放和这个流相关的系统资源。
      voidmark(int?readlimit) :在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。
      void reset() :返回到上一个标记。
      booleanmarkSupported() :测试当前流是否支持mark和reset方法。如果支持,返回true,否则返回false。

2.输出字节流OutputStream


IO 中输出字节流的继承图可见上图,可以看出:

1.    OutputStream是所有的输出字节流的父类,它是一个抽象类。

2.    ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte数组、和本地文件中写入数据。PipedOutputStream是向与其它线程共用的管道中写入数据。

3.    ObjectOutputStream和所有FilterOutputStream的子类都是装饰流。

outputStream中的三个基本的写方法
   abstract void write(int?b):往输出流中写入一个字节。
     void write(byte[]?b) :往输出流中写入数组b中的所有字节。
     void write(byte[]?b, int?off, int?len) :往输出流中写入数组b中从偏移量off开始的len个字节的数据。


其它方法
   void flush() :刷新输出流,强制缓冲区中的输出字节被写出。
     void close() :关闭输出流,释放和这个流相关的系统资源。
 

3.字符输入流Reader


在上面的继承关系图中可以看出:

1.    Reader是所有的输入字符流的父类,它是一个抽象类。

2.    CharReader、StringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。

3.    BufferedReader很明显就是一个装饰器,它和其子类负责装饰其它Reader对象。

4.    FilterReader是所有自定义具体装饰流的父类,其子类PushbackReader对Reader对象进行装饰,会增加一个行号。

5.    InputStreamReader是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream转变为Reader的方法。我们可以从这个类中得到一定的技巧。Reader中各个类的用途和使用方法基本和InputStream中的类使用一致。后面会有Reader与InputStream的对应关系。

主要方法:

     (1) public int read() throws IOException; //读取一个字符,返回值为读取的字符 

     (2) public int read(char cbuf[]) throws IOException; /*读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量*/ 
     (3) public abstract int read(char cbuf[],int off,int len) throws IOException; 
/*读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现*/ 

4.字符输出流Writer

 

在上面的关系图中可以看出:

1.    Writer是所有的输出字符流的父类,它是一个抽象类。

2.    CharArrayWriter、StringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,

3.    BufferedWriter是一个装饰器为Writer提供缓冲功能。

4.    PrintWriter和PrintStream极其类似,功能和使用也非常相似。

5.    OutputStreamWriter是OutputStream到Writer转换的桥梁,它的子类FileWriter其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream极其类似.

 

 

 

主要方法:

(1)  public void write(int c) throws IOException; //将整型值c的低16位写入输出流 
(2)  public void write(char cbuf[]) throws IOException; //将字符数组cbuf[]写入输出流 
(3)  public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 
(4)  public void write(String str) throws IOException; //将字符串str中的字符写入输出流 
(5)  public void write(String str,int off,int len) throws IOException; //将字符串str 中从索引off开始处的len个字符写入输出流 

5.字节流的输入与输出的对应

 

图中蓝色的为主要的对应部分,红色的部分就是不对应部分。从上面的图中可以看出JavaIO中的字节流是极其对称的。“存在及合理”我们看看这些字节流中不太对称的几个类吧!

 

1.    LineNumberInputStream主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。

2.    PushbackInputStream的功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream几乎实现相近的功能。

3.    StringBufferInputStream已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。

4.    SequenceInputStream可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO包中去除,还完全不影响IO包的结构,却让其更“纯洁”――纯洁的Decorator模式。

5.    PrintStream也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO包!System.out和System.out就是PrintStream的实例!

 

6.字符流的输入与输出的对应

 

7.字节流和字符流的区别(重点)

字节流和字符流的区别:(详细可以参见http://blog.csdn.net/qq_25184739/article/details/51203733)    

         节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。

·        读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

·        处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

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

8.非流式文件类--File类


  从定义看,File类是Object的直接子类,同时它继承了Comparable接口可以进行数组的排序。

File类的操作包括文件的创建、删除、重命名、得到路径、创建时间等,以下是文件操作常用的函数。

 

File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。 

File类共提供了三个不同的构造函数,以不同的参数形式灵活地接收文件和目录名信息。

构造函数:
1)File (String   pathname)   
     例:File  f1=new File("FileTest1.txt"); //创建文件对象f1,f1所指的文件是在当前目录下创建的FileTest1.txt
2)File (String  parent  ,  String child)
     例:File f2=new  File(“D:\\dir1","FileTest2.txt") ;//  注意:D:\\dir1目录事先必须存在,否则异常
3)File (File    parent  , String child)
     例:File  f4=new File("\\dir3");
          File  f5=new File(f4,"FileTest5.txt");  //在如果 \\dir3目录不存在使用f4.mkdir()先创建

        一个对应于某磁盘文件或目录的File对象一经创建, 就可以通过调用它的方法来获得文件或目录的属性。    
       1)public boolean exists( ) 判断文件或目录是否存在
       2)public boolean isFile( ) 判断是文件还是目录 
       3)public boolean isDirectory( ) 判断是文件还是目录
       4)public String getName( ) 返回文件名或目录名
       5)public String getPath( ) 返回文件或目录的路径。
       6)public long length( ) 获取文件的长度 
       7)public String[ ] list ( ) 将目录中所有文件名保存在字符串数组中返回。 
       File类中还定义了一些对文件或目录进行管理、操作的方法,常用的方法有:
       1) public boolean renameTo( File newFile );    重命名文件
       2) public void delete( );   删除文件
       3)  public boolean mkdir( ); 创建目录

例子:

1.  public class FileDemo1 {   
2.      public static void main(String[] args) {  
3.          File file = new File("D:" + File.separator + "test.txt");   
4.          if (file.exists()) {   
5.              file.delete();  
6.          } else {   
7.              try {   
8.                  file.createNewFile();  
9.              } catch (IOException e) {  
10.                 // TODO Auto-generated catch block   
11.                 e.printStackTrace();  
12.             }  
13.         }  
14.     }  
15. }  

9.RandomAccessFile类


该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。该对象特点:

 

1.    该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。

2.    该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

 

注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。

10、System类对IO的支持


 针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:

·        System.in(标准输入),通常代表键盘输入。

·        System.out(标准输出):通常写往显示器。

·        System.err(标准错误输出):通常写往显示器。

 标准I/O
      Java程序可通过命令行参数与外界进行简短的信息交换,同时,也规定了与标准输入、输出设备,如键盘、显示器进行信息交换的方式。而通过文件可以与外界进行任意数据形式的信息交换。


1. 命令行参数


public class TestArgs {  
    public static void main(String[] args) {  
        for (int i = 0; i < args.length; i++) {  
            System.out.println("args[" + i + "] is <" + args[i] + ">");  
        }  
    }  
}  


运行命令:java Java C VB


运行结果:

args[0] is <Java>
 
 
args[1] is <C>
 
 
args[2] is <VB>

2. 标准输入,输出数据流

java系统自带的标准数据流:java.lang.System:

java.lang.System   
public final class System  extends Object{   
   static  PrintStream  err;//标准错误流(输出)  
   static  InputStream  in;//标准输入(键盘输入流)  
   static  PrintStream  out;//标准输出流(显示器输出流)  
}  

注意:
(1)System类不能创建对象,只能直接使用它的三个静态成员。
(2)每当main方法被执行时,就自动生成上述三个对象。

1) 标准输出流 System.out

   System.out向标准输出设备输出数据,其数据类型为PrintStream。方法:

      Void print(参数)
      Void println(参数)
2)标准输入流 System.in

    System.in读取标准输入设备数据(从标准输入获取数据,一般是键盘),其数 据类型为InputStream。方法:

        int read()  //返回ASCII码。若,返回值=-1,说明没有读取到任何字节读取工作结束。
        int read(byte[] b)//读入多个字节到缓冲区b中返回值是读入的字节数
例如:

import java.io.*;  
public class StandardInputOutput {  
    public static void main(String args[]) {  
        int b;  
        try {  
            System.out.println("please Input:");  
            while ((b = System.in.read()) != -1) {  
                System.out.print((char) b);  
            }  
        } catch (IOException e) {  
            System.out.println(e.toString());  
        }  
    }  
}  
等待键盘输入,键盘输入什么,就打印出什么:

3)标准错误流

   System.err输出标准错误,其数据类型为PrintStream。可查阅API获得详细说明。

    标准输出通过System.out调用println方法输出参数并换行,而print方法输出参数但不换行。println或print方法都通 过重载实现了输出基本数据类型的多个方法,包括输出参数类型为boolean、char、int、long、float和double。同时,也重载实现 了输出参数类型为char[]、String和Object的方法。其中,print(Object)和println(Object)方法在运行时将调 用参数Object的toString方法。
import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStreamReader;  
  
public class StandardInputOutput {  
    public static void main(String args[]) {  
        String s;  
        // 创建缓冲区阅读器从键盘逐行读入数据  
        InputStreamReader ir = new InputStreamReader(System.in);  
        BufferedReader in = new BufferedReader(ir);  
        System.out.println("Unix系统: ctrl-d 或 ctrl-c 退出"  
                + "\nWindows系统: ctrl-z 退出");  
        try {  
            // 读一行数据,并标准输出至显示器  
            s = in.readLine();  
            // readLine()方法运行时若发生I/O错误,将抛出IOException异常  
            while (s != null) {  
                System.out.println("Read: " + s);  
                s = in.readLine();  
            }  
            // 关闭缓冲阅读器  
            in.close();  
        } catch (IOException e) { // Catch any IO exceptions.  
            e.printStackTrace();  
        }  
    }  
}  

在Java语言中使用字节流和字符流的步骤基本相同,以输入流为例,首先创建一个与数据源相关的流对象,然后利用流对象的方法从流输入数据,最后执行close()方法关闭流。


附加:

 IOException异常类的子类
1.public class  EOFException :   非正常到达文件尾或输入流尾时,抛出这种类型的异常。    

      2.public class FileNotFoundException:   当文件找不到时,抛出的异常。

      3.public class InterruptedIOException: 当I/O操作被中断时,抛出这种类型的异常。
 

网上这文章相对总结到位,我也是经过学习总结的笔记。参考书籍可以看《java编程思想》

参考的文章:

        https://blog.csdn.net/zhaoyanjun6/article/details/54292148

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值