精华内容
下载资源
问答
  • 深入理解Java中的IO

    万次阅读 多人点赞 2016-04-21 01:15:20
    深入理解Java中的IO,个人学习总结。


    深入理解Java中的IO

    引言:

        对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java >

     

    本文的目录视图如下:


    Java IO概要

       a.Java IO中常用的类

         b.Java流类的类结构图

    1.流的概念和作用

    2.Java IO所采用的模型  :

    3.IO流的分类

    4.Java IO流对象

         1.输入字节流InputStream

         2.输出字节流OutputStream

         3.字符输入流Reader

         4.字符输出流Writer

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

    6.字符流与字节流转换

    7.字节流和字符流的区别

    8.File类

    9.RandomAccessFile类

     

    Java IO概要


    为了方便理解与阐述,先引入两张图:

           aJava IO中常用的类


      在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是FileOutputStreamInputStreamWriterReader;一个接口指的是Serializable.掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识了


    Java I/O主要包括如下几个层次,包含三个部分:

      1.流式部分――IO的主体部分;

      2.非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;

      3.其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。


      主要的类如下:

         1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

         2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

         3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

         4.Reader(文件格式操作):抽象类,基于字符的输入操作。

         5. Writer(文件格式操作):抽象类,基于字符的输出操作。

         6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作

     

     JavaIO流的体系结构如图:

     

    bJava流类的类结构图:


    1、流的概念和作用

    流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinking in Java>

    流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。 

    流的作用:为数据源和目的地建立一个输送通道。

     

         Java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流.

     

    2Java IO所采用的模型  


         Java的IO模型设计非常优秀,它使用Decorator(装饰者)模式,按功能划分Stream,您可以动态装配这些Stream,以便获得您需要的功能。

           例如,您需要一个具有缓冲的文件输入流,则应当组合使用FileInputStreamBufferedInputStream 

     

    3IO流的分类

    ·        根据处理数据类型的不同分为:字符流和字节流

    ·        根据数据流向不同分为:输入流和输出流

    ·        按数据来源(去向)分类:

             1File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter 
             2
    、byte[]:ByteArrayInputStream, ByteArrayOutputStream 
             3
    、Char[]: CharArrayReader,CharArrayWriter 
             4
    、String:StringBufferInputStream, StringReader, StringWriter 
             5
    、网络数据流:InputStream,OutputStream, Reader, Writer 

     

    字符流和字节流

    流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。因此Java中的流分为两种:


     1)  
    字节流:数据流中最小的数据单元是字节
     2)  
    字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。

     

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

     

    输入流和输出流

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

    1) 输入流

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


        

    2) 输出流

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

        

            

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

    输入流( Input  Stream )不关心数据源来自何种设备(键盘,文件,网络)。
    输出流( Output Stream )不关心数据的目的是何种设备(键盘,文件,网络)。

    3)特性

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

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

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

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

     

    4Java IO流对象

    1.输入字节流InputStream

     

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

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

    2.    ByteArrayInputStreamStringBufferInputStream(上图的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()
    :测试当前流是否支持markreset方法。如果支持,返回true,否则返回false

    2.输出字节流OutputStream



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

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

    2.    ByteArrayOutputStreamFileOutputStream是两种基本的介质流,它们分别向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.    CharReaderStringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。

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

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

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



    主要方法:

         (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.    CharArrayWriterStringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,

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

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

    5.    OutputStreamWriterOutputStreamWriter转换的桥梁,它的子类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.outSystem.out就是PrintStream的实例!

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


    6.字符流与字节流转换

    转换流的特点:

    1.    其是字符流和字节流之间的桥梁

    2.    可对读取到的字节数据经过指定编码转换成字符

    3.    可对读取到的字符数据经过指定编码转换成字节


    何时使用转换流?

    1.    当字节和字符之间有转换动作时;

    2.    流操作的数据需要编码或解码时。


    具体的对象体现:

    转换流:在IO中还存在一类是转换流,将字节流转换为字符流,同时可以将字符流转化为字节流。

     

    1.    InputStreamReader:字节到字符的桥梁

    2.     OutputStreamWriter:字符到字节的桥梁

     

    OutputStreamWriter(OutStreamout):将字节流以字符流输出。

    InputStreamReader(InputStream in):将字节流以字符流输入。

     

    这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

    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)

     

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


    10System类对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操作被中断时,抛出这种类型的异常。

    参考了大量好的博客文章,总结起来留作学习参考。


    参考文档:

    http://ggicci.blog.163.com/blog/static/2103640962012813997493

    http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html

    http://blog.csdn.net/hguisu/article/details/7418161

    http://blog.csdn.net/taxueyingmei/article/details/7697042

    展开全文
  • 理解Java中的IO

    千次阅读 2016-04-21 15:26:22
    粗略列出并理解Java中的IO 引言:  对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务   本文的目录视图如下: Java IO概要  a.Java IO中常用的类  b.Java流类的类结构图 1.流的概念...

    粗略列出并理解Java中的IO

    引言:

        对程序语言的设计者来说,创建一个好的输入/输出(I/O)系统是一项艰难的任务 < Thinking in Java >

     

    本文的目录视图如下:


    Java IO概要

       a.Java IO中常用的类

         b.Java流类的类结构图

    1.流的概念和作用

    2.Java IO所采用的模型  :

    3.IO流的分类

    4.Java IO流对象

         1.输入字节流InputStream

         2.输出字节流OutputStream

         3.字符输入流Reader

         4.字符输出流Writer

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

    6.字符流与字节流转换

    7.字节流和字符流的区别

    8.File类

    9.RandomAccessFile类

     

    Java IO概要


    为了方便理解与阐述,先引入两张图:

           aJava IO中常用的类


      在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是FileOutputStreamInputStreamWriterReader;一个接口指的是Serializable.掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识了


    Java I/O主要包括如下几个层次,包含三个部分:

      1.流式部分――IO的主体部分;

      2.非流式部分――主要包含一些辅助流式部分的类,如:File类、RandomAccessFile类和FileDescriptor等类;

      3.其他类--文件读取部分的与安全相关的类,如:SerializablePermission类,以及与本地操作系统相关的文件系统的类,如:FileSystem类和Win32FileSystem类和WinNTFileSystem类。


      主要的类如下:

         1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

         2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

         3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

         4.Reader(文件格式操作):抽象类,基于字符的输入操作。

         5. Writer(文件格式操作):抽象类,基于字符的输出操作。

         6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作

     

     JavaIO流的体系结构如图:

     

    bJava流类的类结构图:


    1、流的概念和作用

    流:代表任何有能力产出数据的数据源对象或者是有能力接受数据的接收端对象<Thinking in Java>

    流的本质:数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。 

    流的作用:为数据源和目的地建立一个输送通道。

     

         Java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流.

     

    2Java IO所采用的模型  


         Java的IO模型设计非常优秀,它使用Decorator(装饰者)模式,按功能划分Stream,您可以动态装配这些Stream,以便获得您需要的功能。

           例如,您需要一个具有缓冲的文件输入流,则应当组合使用FileInputStreamBufferedInputStream 

     

    3IO流的分类

    ·        根据处理数据类型的不同分为:字符流和字节流

    ·        根据数据流向不同分为:输入流和输出流

    ·        按数据来源(去向)分类:

             1File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter 
             2
    、byte[]:ByteArrayInputStream, ByteArrayOutputStream 
             3
    、Char[]: CharArrayReader,CharArrayWriter 
             4
    、String:StringBufferInputStream, StringReader, StringWriter 
             5
    、网络数据流:InputStream,OutputStream, Reader, Writer 

     

    字符流和字节流

    流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据。因此Java中的流分为两种:


     1)  
    字节流:数据流中最小的数据单元是字节
     2)  
    字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。

     

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

     

    输入流和输出流

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

    1) 输入流

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


        

    2) 输出流

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

        

            

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

    输入流( Input  Stream )不关心数据源来自何种设备(键盘,文件,网络)。
    输出流( Output Stream )不关心数据的目的是何种设备(键盘,文件,网络)。

    3)特性

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

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

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

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

     

    4Java IO流对象

    1.输入字节流InputStream

     

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

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

    2.    ByteArrayInputStreamStringBufferInputStream(上图的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() 
    :测试当前流是否支持markreset方法。如果支持,返回true,否则返回false

    2.输出字节流OutputStream



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

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

    2.    ByteArrayOutputStreamFileOutputStream是两种基本的介质流,它们分别向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.    CharReaderStringReader是两种基本的介质流,它们分别将Char数组、String中读取数据。PipedReader是从与其它线程共用的管道中读取数据。

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

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

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



    主要方法:

         (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.    CharArrayWriterStringWriter是两种基本的介质流,它们分别向Char数组、String中写入数据。PipedWriter是向与其它线程共用的管道中写入数据,

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

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

    5.    OutputStreamWriterOutputStreamWriter转换的桥梁,它的子类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.outSystem.out就是PrintStream的实例!

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


    6.字符流与字节流转换

    转换流的特点:

    1.    其是字符流和字节流之间的桥梁

    2.    可对读取到的字节数据经过指定编码转换成字符

    3.    可对读取到的字符数据经过指定编码转换成字节


    何时使用转换流?

    1.    当字节和字符之间有转换动作时;

    2.    流操作的数据需要编码或解码时。


    具体的对象体现:

    转换流:在IO中还存在一类是转换流,将字节流转换为字符流,同时可以将字符流转化为字节流。

     

    1.    InputStreamReader:字节到字符的桥梁

    2.     OutputStreamWriter:字符到字节的桥梁

     

    OutputStreamWriter(OutStreamout):将字节流以字符流输出。

    InputStreamReader(InputStream in):将字节流以字符流输入。

     

    这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

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

    字节流和字符流的区别(详细可以参见ttp://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( ); 创建目录

    例子:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. 1.  public class FileDemo1 {     
    2. 2.      public static void main(String[] args) {    
    3. 3.          File file = new File("D:" + File.separator + "test.txt");     
    4. 4.          if (file.exists()) {     
    5. 5.              file.delete();    
    6. 6.          } else {     
    7. 7.              try {     
    8. 8.                  file.createNewFile();    
    9. 9.              } catch (IOException e) {    
    10. 10.                 // TODO Auto-generated catch block     
    11. 11.                 e.printStackTrace();    
    12. 12.             }    
    13. 13.         }    
    14. 14.     }    
    15. 15. }    

    9.RandomAccessFile


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

     

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

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

     

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


    10System类对IO的支持

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

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

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

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

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


    1. 命令行参数

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. public class TestArgs {    
    2.     public static void main(String[] args) {    
    3.         for (int i = 0; i < args.length; i++) {    
    4.             System.out.println("args[" + i + "] is <" + args[i] + ">");    
    5.         }    
    6.     }    
    7. }    


    运行命令:java Java C VB


    运行结果:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. args[0] is <Java>  
    2.   
    3.   
    4. args[1] is <C>  
    5.   
    6.   
    7. args[2] is <VB>  

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


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

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. java.lang.System     
    2. public final class System  extends Object{     
    3.    static  PrintStream  err;//标准错误流(输出)    
    4.    static  InputStream  in;//标准输入(键盘输入流)    
    5.    static  PrintStream  out;//标准输出流(显示器输出流)    
    6. }    

    注意:
    (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中返回值是读入的字节数
    例如:

    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. import java.io.*;    
    2. public class StandardInputOutput {    
    3.     public static void main(String args[]) {    
    4.         int b;    
    5.         try {    
    6.             System.out.println("please Input:");    
    7.             while ((b = System.in.read()) != -1) {    
    8.                 System.out.print((char) b);    
    9.             }    
    10.         } catch (IOException e) {    
    11.             System.out.println(e.toString());    
    12.         }    
    13.     }    
    14. }    
    等待键盘输入,键盘输入什么,就打印出什么:

    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方法。
    [java] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. import java.io.BufferedReader;    
    2. import java.io.IOException;    
    3. import java.io.InputStreamReader;    
    4.     
    5. public class StandardInputOutput {    
    6.     public static void main(String args[]) {    
    7.         String s;    
    8.         // 创建缓冲区阅读器从键盘逐行读入数据    
    9.         InputStreamReader ir = new InputStreamReader(System.in);    
    10.         BufferedReader in = new BufferedReader(ir);    
    11.         System.out.println("Unix系统: ctrl-d 或 ctrl-c 退出"    
    12.                 + "\nWindows系统: ctrl-z 退出");    
    13.         try {    
    14.             // 读一行数据,并标准输出至显示器    
    15.             s = in.readLine();    
    16.             // readLine()方法运行时若发生I/O错误,将抛出IOException异常    
    17.             while (s != null) {    
    18.                 System.out.println("Read: " + s);    
    19.                 s = in.readLine();    
    20.             }    
    21.             // 关闭缓冲阅读器    
    22.             in.close();    
    23.         } catch (IOException e) { // Catch any IO exceptions.    
    24.             e.printStackTrace();    
    25.         }    
    26.     }    
    27. }    

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


    附加:

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

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

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

    参考了大量好的博客文章,总结起来留作学习参考。


    参考文档:

    http://ggicci.blog.163.com/blog/static/2103640962012813997493

    http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html

    http://blog.csdn.net/hguisu/article/details/7418161

    http://blog.csdn.net/taxueyingmei/article/details/7697042

    展开全文
  • java中的IO操作总结

    千次阅读 2019-02-22 14:30:59
    java中的IO操作 在java中IO涉及的范围比较大,本文主要针对文件内容的读写 对于文件内容的操作主要分为两大类: 字符流:有两个抽象类 writer Reader  其对应子类FileWriter和FileReader可实现文件的读写...

    java中的IO操作

    在java中IO涉及的范围比较大,本文主要针对文件内容的读写

    对于文件内容的操作主要分为两大类:

    • 字符流:有两个抽象类
      • writer
      • Reader

            其对应子类FileWriter和FileReader可实现文件的读写操作

            BufferedWriter和BufferedReader能够提供缓冲区功能,用以提高效率。

    • 字节流:有两个抽象类
      • InputStream
      • OutputStream

            其对应子类FileInputStream和FileOutputStream可实现文件的读写

            BufferedInputStream和BufferedOutputStream能够提供缓冲区功能,用以提高效率

    字符流

    1.字符流的写入

    package test1;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class IOdemo01 {
    	
    	public static void main(String[] args) {
    		//创建要操作的文件路径和名称
    		String path = "D:\\xu001\\demo01.txt";
    		FileWriter w = null;
    		//由于IO操作会抛出异常,因此在try语句块的外部定义FileWriter的引用
    		try {
    			//以path为路径添加一个新的FileWriter对象
    			//如果需要追加数据,而不是覆盖,则使用FileWriter(path,true)构造方法
    			w = new FileWriter(path);
    			//将字符串写入到流中,\r\n表示换行
    			w.write("Alice is a beautiful girl\r\n");
    			//如果想马上看到写入的效果,则需要调用w.flush()方法
    			w.flush();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			//若前面的代码发生异常,那么就无法产生w对象
    			//因此要做出判断,以免发生空指针异常
    			if (w!=null) {
    				try {
    					//关闭资源需要再次捕捉异常
    					w.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }

    编译之后,在目录下面生成文件,并写入字符串:

    2.字符流的读取

    package test1;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    public class IOdemo02 {
    	
    	public static void main(String[] args) {
    		//目标文件的路径
    		String path = "D:\\xu001\\demo01.txt";
    		FileReader r = null;
    		try {
    			//读入到字符数组
    			r = new FileReader(path);
    			char [] buf = new char[1024];
    			try {
    				int temp = r.read(buf);
    				System.out.println(new String(buf,0,temp));
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}	
    			
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			if (r!=null) {
    				try {
    					r.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }

    编译之后的效果:

    3.文本文件的复制

    package test1;
    
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class IOdemo03 {
    	
    	public static void main(String[] args) {
    		
    		String doc = "D:\\xu001\\demo01.txt";
    		String copy = "D:\\xu001\\demo02.txt";
    		FileReader r = null;
    		FileWriter w = null;
    		
    		try {
    			r = new FileReader(doc);
    			w = new FileWriter(copy);
    			//单个字符写入
    			int temp = 0;
    			while((temp = r.read()) != -1){
    				w.write(temp);
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			//分别判断是否是空指针引用,然后关闭流
    			if (r != null) {
    				try {
    					r.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			if (w != null) {
    				try {
    					w.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    

    编译之后的效果:

    4.利用字符流缓冲区来进行文本文件的复制

    package test1;
    
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.FileNotFoundException;
    
    public class IOdemo04 {
    	
    	public static void main(String[] args) {
    		String doc = "D:\\xu001\\demo01.txt";
    		String copy = "D:\\xu001\\demo03.txt";
    		FileReader r = null;
    		FileWriter w = null;
    		//创建缓冲区的引用
    		BufferedReader br = null;
    		BufferedWriter bw = null;
    		try {
    			r = new FileReader(doc);
    			w = new FileWriter(copy);
    			//创建缓冲区对象
    			//将需要提高效率的FileReader和FileWriter对象放入其构造函数内
    			br = new BufferedReader(r);
    			bw = new BufferedWriter(w);
    			String line = null;
    			//读取行,知道返回null
    			//readLine()方法只返回换行符之前的数据
    			while((line = br.readLine()) != null){
    				//使用bufferedWriter对象写入方法
    				bw.write(line);
    				//写完文件内容之后换行
    				//newLine()方法依据平台而定
    				bw.newLine();
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			//此处不需要捕捉FileReader和FileWriter对象的异常,关闭缓冲区就是关闭缓冲区中的流对象
    			if (br != null) {
    				try {
    					br.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			if (bw != null) {
    				try {
    					bw.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}	
    	}
    }
    

    编译之后的效果如下:

     

    字节流

    5.字节流的写入

    package test1;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class IOdemo05 {
    	
    	public static void main(String[] args) {
    		
    		String path = "D:\\xu001\\demo01.txt";
    		FileOutputStream o = null;
    		
    		try {
    			o = new FileOutputStream(path);
    			String str = "peter is a good boy\r\n";
    			byte []buf = str.getBytes();
    			//因为字符串是一个对象,能直接调用方法
    			try {
    				o.write(buf);
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			if (o!=null) {
    				try {
    					o.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}	
    	}
    }
    

    编译之后的效果如下:

    6.字节流的读取

    package test1;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class IOdemo06 {
    	
    	public static void main(String[] args) {
    		
    		String path = "D:\\xu001\\demo01.txt";
    		FileInputStream i = null;
    		try {
    			i = new FileInputStream(path);
    			//数组循环读取
    			byte [] buf = new byte[1024];
    			int len = 0;
    			try {
    				while((len = i.read(buf)) != -1){
    				System.out.println(new String(buf,0,len));	
    				}
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			if (i != null) {
    				try {
    					i.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    

    编译之后的效果如下:

    7.二进制文件的复制

    package test1;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class IOdemo07 {
    	
    	public static void main(String[] args) {
    		
    		String bin = "D:\\xu001\\abc.jpg";
    		String copy = "D:\\xu002\\abc.jpg";
    		
    		FileInputStream i = null;
    		FileOutputStream o = null;
    		
    		try {
    			i = new FileInputStream(bin);
    			o = new FileOutputStream(copy);
    			//循环的方式读入写出文件,从而完成复制
    			byte [] buf = new byte[1024];
    			int temp = 0;
    			try {
    				while((temp = i.read()) != -1){
    					o.write(buf,0,temp);
    				}
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			if (i != null) {
    				try {
    					i.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			if (o != null) {
    				try {
    					o.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    

    编译之后的效果如下:

    8.利用字节流的缓冲区进行二进制文件的复制

    package test1;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class IOdemo08 {
    	
    	public static void main(String[] args) {
    		
    		String bin = "D:\\xu001\\abc.jpg";
    		String copy = "D:\\xu002\\abc.jpg";
    		
    		FileInputStream i = null;
    		FileOutputStream o = null;
    		
    		BufferedInputStream bi = null;
    		BufferedOutputStream bo = null;
    		
    		try {
    			i = new FileInputStream(bin);
    			o = new FileOutputStream(copy);
    			bi = new BufferedInputStream(i);
    			bo = new BufferedOutputStream(o);
    			byte [] buf = new byte[1024];
    			int temp = 0;
    			try {
    				while((temp = bi.read(buf)) != -1){
    					bo.write(buf,0,temp);
    				}
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			if (bi != null) {
    				try {
    					bi.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    			if (bo != null) {
    				try {
    					bo.close();
    				} catch (IOException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    

    编译之后的效果如下:

    在最后讲一下使用字节流和字符流的具体情况:

    字符流,用于操作类似文本文件或者带有字符文件的场合较多

    字节流,常用于操作那些无法直接获取文本信息的二进制文件,比如图片、MP3、视频等

    说白了任何文件在硬盘上都是以字节存储的,只不过字符流在操作文本上更方便一点而已

    在文中为什么会用到缓冲区呢?

    对于常用的下载类软件包括硬盘,都设有缓存区的功能;我们可以试想一下,如果一有数据,不论大小就开始读写,势必会给硬盘造成很大负担,因此采用换成去能够在读写大文件时有效提高效率。

    展开全文
  • Java中的IO流总结

    千次阅读 2016-08-03 20:03:22
    Java中的IO流总结 1. 流的继承关系,以及字节流和字符流。 2. 节点流FileOutputStream和FileInputStream和处理流BufferedInputStream和BufferedOutputStream。以及对应的FileOutputWriter,FileInputReader,...
                Java中的IO流总结
    

    1. 流的继承关系,以及字节流和字符流。
    2. 节点流FileOutputStream和FileInputStream和处理流BufferedInputStream和BufferedOutputStream。以及对应的FileOutputWriter,FileInputReader,BufferedInputReader,BufferedOutputWriter。
    3. 转换流InputStreamReader和OutputStreamWriter

        一:流的继承关系
    

    字节流
    这里写图片描述

    字符流
    这里写图片描述

    字符流和字节流的使用范围:字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。

    二:处理流BufferedReader,BufferedWriter,BufferedInputStream
    

    ,BufferedOutputsStream,都要包上一层节点流。也就是说处理流是在节点流的基础之上进行的,带有Buffered的流又称为缓冲流,缓冲流处理文件的输入输出的速度是最快的。所以一般缓冲流的使用比较多。
    下面是两个简单的文件复制的实例:

    public class MycopyTest {
        public static void main(String[] args) {
            File src = new File("D:/1.jpg");
            // D:/1.jpg必须的存在不然会报错
            File dest = new File("D:/2.jpg");
            // 如果D:/2.jpg存在则覆盖,如果不存在则新建
            streamCopy(src, dest);
        }
    private static void readCopy(File src,File dest)
        {
            FileReader fr=null;
            FileWriter fw=null;
            BufferedReader br=null;
            BufferedWriter bw=null;
            try {
                fr=new FileReader(src);
                fw=new FileWriter(dest);
                br=new BufferedReader(fr);
                bw=new BufferedWriter(fw);
                String str;
                while((str=br.readLine())!=null)
                {
                    bw.write(str);
                    bw.newLine();
                }
            }catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                bw.close();
                br.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
        private static void streamCopy(File src, File dest) {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            BufferedInputStream bis = null;
            BufferedOutputStream bos = null;
            try {
                fis = new FileInputStream(src);
                fos = new FileOutputStream(dest);
                bis = new BufferedInputStream(fis);
                bos = new BufferedOutputStream(fos);
                int len;
                byte[] b = new byte[1024];
                while ((len = bis.read(b)) != -1) {
                    bos.write(b, 0, len);
                    // bos.write(b,0,len);是把读到数组的大小字节写入
                    // bos.write(b);最后一次如果数组未写满的话就会多读。
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                bos.close();
                bis.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    三:转换流InputStreamReader和OutputStreamWriter
    

    这里写图片描述

    转换流的作用,文本文件在硬盘中以字节流的形式存储时,通过InputStreamReader读取后转化为字符流给程序处理,程序处理的字符流通过OutputStreamWriter转换为字节流保存。

    public class InputStreamWriterTest {
        public static void main(String[] args) {
            File src = new File("D:/Files/狗屁.txt");
            File dest = new File("D:/Files/斯密斯.txt");
            BufferedWriter bw = null;
            BufferedReader br = null;
            FileInputStream fis = null;
            FileOutputStream fos = null;
            try {
                fis = new FileInputStream(src);
                fos = new FileOutputStream(dest);
                InputStreamReader ir = new InputStreamReader(fis, "GBK");
                OutputStreamWriter ow = new OutputStreamWriter(fos, "GBK");
                bw = new BufferedWriter(ow);
                br = new BufferedReader(ir);
                String str;
                while ((str = br.readLine()) != null) {
                    bw.write(str);
                    bw.newLine();
                    bw.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                bw.close();
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    展开全文
  • java中的IO基础

    千次阅读 2013-03-31 22:10:46
    java中的IO基础
  • java中的IO基础3

    千次阅读 2013-03-31 22:11:05
    java中的IO基础
  • java中的IO基础2

    千次阅读 2013-03-31 22:10:57
    java中的IO基础
  • Java中的IO操作

    千次阅读 2018-03-23 21:46:47
    一、java的io发生在哪? 这个问题,我们必须首先明确下。io发生在内存和硬盘之间。因为程序在内存运行。我们需要将硬盘的文件数据读入到内存,再将数据从内存输出到硬盘,所以我们就有了IO操作。i和o是分别...
  • Java中的IO流修改

    千次阅读 2017-02-10 12:47:36
    Java.IO Java的核心库java.io提供了全面的IO接口。包括:文件读写、标准设备输出等。Java中IO是以流为基础进行输入输出的,...字符流:数据流中的最小的数据单元是字符,一次读入读出16位二进制,java中的字符是Unicod
  • 【Java】Java中的IO

    千次阅读 2017-08-16 13:03:51
    摘要:本文主要讲解了Java中 IO使用,包括流概念、流分类及使用实例等
  • JAVA中的IO阻塞

    千次阅读 2018-03-05 15:08:22
    1.同步阻塞IOJAVA BIO) 在JDK1.4之前,建立网络连接采用BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Sokcet来对服务端进行通讯,默认情况下服务端需要对每个请求建立一堆县城等待请求,而...
  • Java中的IO流(三)

    千次阅读 2020-01-04 15:45:58
    IO流练习: 复制文本文件: 4种: 基本字符流一次读写一个字符 基本字符流一次读写一个字符数组 高效字符流一次读写一个字符 高效字符流一次读写一个字符数组 数据源:a.txt ...import java.io.File...
  • Java中的IO流(一)

    千次阅读 2020-01-04 15:01:18
    IOJava对数据操作是通过流方式,IO流用来处理设备之间数据传输,上传文件和下载文件,Java用于操作流对象都在IO包中。 根据流向可分为:输入流、输出流 根据数据类型可分为: 字节流:字节输入流、字节...
  • byte b = (byte) fin.read();
  • 轻松理解java中的IO与NIO

    千次阅读 2018-04-12 15:05:40
    Java语言在IO设计方面是比较成功,不仅是面向对象,而且利用装饰器设计模式(后面会写针对设计模式文章)减少了大量类,提供了较好扩展性。那Java IO怎么写入/读取数据?Java IO类库可以分为输入流和输出流...
  • 深入分析Java I/O 工作机制 作者:egg 邮箱:xtfggef@gmail.com 微博:http://weibo.com/xtfggef 博客:http://blog.csdn.net/zhangerqing ...IOJava及众多编程语言很重要一块,同时很多程序
  • java中的IO整理

    千次阅读 2012-12-11 21:31:54
    写在前面:本文章基本覆盖了java IO的全部内容,javaIO没有涉及,因为我想和这个分开,以突出那个重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面。照旧,文章依旧以例子为主,因为讲解内容的java...
  • java中的io

    千次阅读 2012-11-28 20:43:54
    写在前面:本文章基本覆盖了java IO的全部内容,javaIO没有涉及,因为我想和这个分开,以突出那个重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面。照旧,文章 依旧以例子为主,因为讲解内容的java...
  • java中的iobuffer

    千次阅读 2013-05-31 09:52:46
    在做crc校验过程遇到了iobuffer转换成string问题,自己找了点资料写了个简单方法。  Java代码  package minaUDP;    import java.nio.ByteOrder;  import java.nio.charset....
  • Java中的IO流(二)

    千次阅读 2020-01-04 15:27:04
    String中的编码和解码问题。 编码:把我们能够看懂的字符转换为看不懂的数据 解码:把我们看不懂的数据转换为看得懂的字符 public byte[] getBytes(String charsetName) 按照给定的编码方式,编码字节数组(gbk,utf-...
  • java中的IO操作总结(一

    千次阅读 2016-10-30 17:11:46
    java中IO涉及范围比较大,这里主要讨论针对文件内容读写 其他知识点将放置后续章节(我想,文章太长了,谁都没耐心翻到最后)   对于文件内容操作主要分为两大类 分别是:  字符流  ...
  • java中的IO流使用情况

    2015-09-26 12:42:00
    java中有很多读取和写入文件操作 像FileWirter Writer Reader BufferWriter 等 我一直区分不清这几个特点,有没有大神帮忙处理下,通常什么情况使用什么比较好。各有那些优点和缺点

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 59,442
精华内容 23,776
关键字:

java中的io

java 订阅