java的IO操作:字節流與字符流操作


流的概念

  

  程序中的輸入輸出都是以流形式,流中保存的實際上都是字節文件。

字節流與字符流

  字節流的操作:

    1)輸入:inputStream,

    2)輸出:outPutStream;

  字符流的操作:

    1)輸入主要使用:write類。

    2)輸出主要使用:reader類。

  內容操作就四個類。

操作流程:

  

  使用File類操作一定有路徑問題,注意分隔符:

  實際上四個操作類都是抽象類(區別接口,抽象類的成員都是抽象,並且只能單繼承,接口可以有全局變量,但是接口可以多繼承

  IO操作屬於資源操作,對於資源操作,操作最后必須關閉,否則有可能出現未知錯誤

字節流

  字節流主要操作byte類型數據,以byte數組為准,注意操作類為字節輸出流:outputStream,字節輸入流:inputStream,類。

  Byte是字節,肯定使用字節流操作,所有的數據基本都可以使用byte數組表示出來。

OutputStream類

  字節輸出流的最大父類:定義如下: 

public abstract class OutputStream extends Object implements  Closeable ,Flushable;

  Closeable表示可以關閉的操作,因為程序最后要關閉。

  Flushable表示刷新,清空內存中數據。

  此類是抽象類,所以要想使用此類,必須要通過子類實例化父類對象

  那么要操作的是一個文件,則可以使用FileOutputStream類,通過向上轉型之后,可以為OutputStream實例化。

  

  FileOutputStream構造方法:

public FileOutputStream( File file) throws FielNotFoundException

  可見FileOutputStream需要操作File類的對象,並且有異常處理。

  

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo01{
    public static void main(String args[]) throws Exception{ // 異常拋出,不處理 // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步通過子類實例化父類對象,注意下面是通過向上轉型,實例化父類對象。
        OutputStream out = null ;    // 准備好一個輸出的對象
        out = new FileOutputStream(f) ; // 通過對象多態性,進行實例化 // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串
        byte b[] = str.getBytes() ;            // 只能輸出byte數組,所以將字符串變為byte數組
       out.write(b) ; // 將內容輸出,保存文件 // 第4步、關閉輸出流
      out.close() ; // 關閉輸出流
    }
};

  1)因為FielOutputStream有異常,wire()方法也有異常,為了節省操作,可以在主方法拋出異常,不處理

  2)輸出字符串:可以先用方法 getBytes()一次性讀取字符串字節數組中,然后再把字節數組輸出。

  3)OutputStream的實例對象調用write(byte []b)方法,把數組輸出。

  4)在操作時候,如果文件本身不存在,就會為用戶自動創建新文件。

  在操作輸出流的時候也可以使用write(int i)的方式寫出數據。

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo02{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        OutputStream out = null ;    // 准備好一個輸出的對象
        out = new FileOutputStream(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串
        byte b[] = str.getBytes() ;            // 只能輸出byte數組,所以將字符串變為byte數組
        for(int i=0;i<b.length;i++){        // 采用循環方式寫入 out.write(b[i]) ; // 每次只寫入一個內容
        }
        // 第4步、關閉輸出流
        out.close() ;                        // 關閉輸出流
    }
};

  以上操作在輸入數據后,以前的數據不存在。因為在IO操作中默認是將其覆蓋。如果要想執行追加功能,必須設置追加操作

  找到FileOutputStream類:

public FileOutputStream(File file,bool append)throws FileNotFoundException

  在構造方法中,如果append的值設為true,表示在文件的末尾追加

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo03{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        OutputStream out = null ;    // 准備好一個輸出的對象
        out = new FileOutputStream(f,true) ; // 此處表示在文件末尾追加內容 // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串
        byte b[] = str.getBytes() ;            // 只能輸出byte數組,所以將字符串變為byte數組
        for(int i=0;i<b.length;i++){        // 采用循環方式寫入
            out.write(b[i]) ;    // 每次只寫入一個內容
        }
        // 第4步、關閉輸出流
        out.close() ;                        // 關閉輸出流
    }
};

  上面是在末尾追加,沒換行,如果要換行,在要添加的文子前面,使用“\r\n”完成

如:String str="\r\n在這里追加";

package Thread1;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo1 {
    // 所有的異常直接拋出,程序中不再進行處理
    public static void main(String args[]) throws Exception{
        File f=new File("D:\\outputStream.txt");
        OutputStream out=new FileOutputStream(f,true);
        String str="\r\n在這里追加";
        byte[]b=str.getBytes();
        out.write(b);
        out.close();
    }
};

  運行結果:

字節輸入流InputStream

  定義:public abstract class inputStream extends Object implements Clossablle;

與OutputStream類似,也是抽象類,必須依靠子類,如果從文件讀取,肯定是FileInputStream;

  構造方法:

public FileInputStream(File file) throws FileNotFoundException

  要處理異常,參數需要File對象,向上轉型。

  

  以read(byte[] b)形式讀取到數組中。

package Thread1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class demo1 {
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
    // 第1步、使用File類找到一個文件
            File f= new File("d:" + File.separator + "outputStream.txt") ;    // 聲明File對象
            // 第2步、通過子類實例化父類對象
            InputStream input=null;     // 准備好一個輸入的對象
            input = new FileInputStream(f)  ;    // 通過對象多態性,進行實例化 // 第3步、進行讀操作
            byte b[] = new byte[1024] ;        // 所有的內容都讀到此數組之中
            input.read(b) ; // 讀取內容 // 第4步、關閉輸出流
            input.close() ;                        // 關閉輸出流
            System.out.println("內容為:" + new String(b)) ;    // 把byte數組變為字符串輸出
}
};

  運行結果:

內容為:hello moto在這里追加
在這里追加

  1)定義一個byte類型的數組對象,用於讀取從File類的指定文件的內容。

  2)InputStream通過子類,利用多態性,向上轉型,實例化對象。

  3)InputStream對象調用read(byte b[])方法,把File中的內容讀取給b[]數組。

  此刻雖然讀取出來了,但是存在問題,文件沒有這么大,但是開辟了這么大空間,浪費內存。

能不能根據文件大小開辟數組空間?

  如果要想知道文件大小,直接使用File類即可。f.length()方法獲得文件的大小,注意同時要類型轉換

package Thread1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class demo1 {
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "outputStream.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        InputStream input = null ;    // 准備好一個輸入的對象
        input = new FileInputStream(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
        byte b[] = new byte[(int)f.length()] ; // 數組大小由文件決定
        int len = input.read(b) ;        // 讀取內容
        // 第4步、關閉輸出流
        input.close() ;                        // 關閉輸出流\
        System.out.println("讀入數據的長度:" + len) ;
        System.out.println("內容為:" + new String(b)) ; // 把byte數組變為字符串輸出
    }
};

  運行結果:

讀入數據的長度:32
內容為:hello moto在這里追加
在這里追加

new String(b),因為讀取的時候是從字符類型先轉化成byte類型,所以輸出要轉換成String類型。

這里其實是String類的構造方法,相當於實例化了一個String類的對象,生成了一個String 變量。

 

以上是利用byte數組形式讀取文件。read(byte [] b)

另外一個常用的讀取方法read();字節一個個的讀

abstract  int read() 從輸入流中讀取數據的下一個字節 

注意:read()方法的返回結果是int類型,所以對於字節需要轉化類型

 

package 類集;
import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
public class InputStreamDemo04{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        InputStream input = null ;    // 准備好一個輸入的對象
        input = new FileInputStream(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
        byte b[] = new byte[(int)f.length()] ; // 數組大小由文件決定
        for(int i=0;i<b.length;i++){
            b[i] = (byte)input.read() ; // 讀取內容
        }
        // 第4步、關閉輸出流
        input.close() ;                        // 關閉輸出流\
        System.out.println("內容為:" + new String(b)) ;    // 把byte數組變為字符串輸出
    }
};

 

以上操作只適合知道輸入流大小的時候,如果現在不知道大小呢?

package 類集;
import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
public class InputStreamDemo05{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        InputStream input = null ;    // 准備好一個輸入的對象
        input = new FileInputStream(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
        byte b[] = new byte[1024] ;        // 數組大小由文件決定
        int len = 0 ; 
        int temp = 0 ;            // 接收每一個讀取進來的數據
        while((temp=input.read())!=-1){  //這里先把字節讀取出來,賦值給temp,如果temp不等於-1,表示還有內容,文件沒有讀完
            b[len] = (byte)temp ;
            len++ ;
        }
        // 第4步、關閉輸出流
        input.close() ;                        // 關閉輸出流\
        System.out.println("內容為:" + new String(b,0,len)) ;    // 把byte數組變為字符串輸出
    }
};

當不知道讀取的內容有多大的時候,就只能通過以讀取的內容是否為-1為讀完的標志

這個是常用的字節流操作方法:

     InputStream input = null ;    // 准備好一個輸入的對象
        input = new FileInputStream(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
        byte b[] = new byte[1024] ;        // 數組大小由文件決定
        int len = 0 ; 
        int temp = 0 ;            // 接收每一個讀取進來的數據
        while((temp=input.read())!=-1){  //這里先把字節讀取出來,賦值給temp,如果temp不等於-1,表示還有內容,文件沒有讀完
            b[len] = (byte)temp ;
            len++ ;
        }

 

 

字符流操作

字符輸入流:Writer類

字符輸出流:Reader類。

Writer類

常用方法:

字符流比字節流操作好在一點,就是可以直接輸出字符串了。不用跟之前一樣進行轉換操作

代碼實例:

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo01{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        Writer out = null ;    // 准備好一個輸出的對象
        out = new FileWriter(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串,注意,這里不用跟字節流操作一樣轉換成Byte數組類型。
        out.write(str) ; // 將內容輸出,保存文件 // 第4步、關閉輸出流
        out.close() ;                        // 關閉輸出流
    }
};

使用字符流默認情況下依然覆蓋已有文件,要想追加,則在FileWriter上加一個追加標記即可。

package 類集;
import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo02{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        Writer out = null ;    // 准備好一個輸出的對象
        out = new FileWriter(f,true)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行寫操作
        String str = "\r\nLIXINGHUA\r\nHello World!!!" ;        // 准備一個字符串
        out.write(str) ;                        // 將內容輸出,保存文件
        // 第4步、關閉輸出流
        out.close() ;                        // 關閉輸出流
    }
};

字符輸入流:Reader()

常用方法

以字符數組形式讀取出數組。

package 類集;
import java.io.File ;
import java.io.Reader ;
import java.io.FileReader ;
public class ReaderDemo01{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        Reader input = null ;    // 准備好一個輸入的對象
        input = new FileReader(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
        char c[] = new char[1024] ;        // 所有的內容都讀到此數組之中
        int len = input.read(c) ; // 讀取內容 // 第4步、關閉輸出流
        input.close() ;                        // 關閉輸出流
        System.out.println("內容為:" + new String(c,0,len)) ;    // 把字符數組變為字符串輸出
    }
};

輸出結果:

內容為:hello    fsdfsdfshello    
LIXINGHUA
Hello World!!!

也可以以循環方式,通過文件是否讀到底判斷。

import java.io.File ;
import java.io.Reader ;
import java.io.FileReader ;
public class ReaderDemo02{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "test.txt") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        Reader input = null ;    // 准備好一個輸入的對象
        input = new FileReader(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行讀操作
         char c[] = new char[1024] ; // 所有的內容都讀到此數組之中 int temp = 0 ; // 接收每一個內容 int len = 0 ; // 讀取內容
        while((temp=input.read())!=-1){
            // 如果不是-1就表示還有內容,可以繼續讀取
             c[len] = (char)temp ; len++ ;
        }
        // 第4步、關閉輸出流
        input.close() ;                        // 關閉輸出流
        System.out.println("內容為:" + new String(c,0,len)) ;    // 把字符數組變為字符串輸出
    }
};

 

字符流與字節流的區別

字節和字符使用非常相似,有哪些不同呢?

1,字節流不會用到緩存,字符流會用到緩存。

通過代碼驗證字節流使用到了緩存。

 字節流操作:

package 類集;
import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo05{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        OutputStream out = null ;    // 准備好一個輸出的對象
        out = new FileOutputStream(f)  ;    // 實例化
        // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串
        byte b[] = str.getBytes() ;            // 只能輸出byte數組,所以將字符串變為byte數組
        out.write(b) ;        // 寫入數據
        // 第4步、關閉輸出流
        // out.close() ; // 關閉輸出流
    }
};

結果在指定目錄成功輸出內容。

在使用字節流操作中,即使沒有關閉,最終也可以輸出

字符流操作:

package 類集;
import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo03{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
        File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
        // 第2步、通過子類實例化父類對象
        Writer out = null ;    // 准備好一個輸出的對象
        out = new FileWriter(f)  ;    // 通過對象多態性,進行實例化
        // 第3步、進行寫操作
        String str = "Hello World!!!" ;        // 准備一個字符串
        out.write(str) ;                        // 將內容輸出,保存文件
        // 第4步、關閉輸出流
        // out.close() ; // 此時,沒有關閉
    }
};

運行結果:為空。

以上操作沒有輸出任何內容,所有的內容現在保存在緩沖區當中,如果執行關閉的時候,會強制性的刷新緩沖區,所以可以把內容輸出

abstract  void close() 關閉此流,但要先刷新它 

如果現在沒有關閉的話,也可以強制調用刷新方法

abstract  void flush()  刷新該流的緩沖。 
package 類集;
import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo03{
    public static void main(String args[]) throws Exception{    // 異常拋出,不處理
        // 第1步、使用File類找到一個文件
            File f= new File("d:" + File.separator + "te.text") ;    // 聲明File對象
            // 第2步、通過子類實例化父類對象
            Writer out = null ;    // 准備好一個輸出的對象
            out = new FileWriter(f)  ;    // 通過對象多態性,進行實例化
            // 第3步、進行寫操作
            String str = "Hello World!!!" ;        // 准備一個字符串
            out.write(str) ; // 將內容輸出,保存文件 // 第4步、關閉輸出流
            out.flush() ; // 強制性清空緩沖區中的內容 // out.close() ;            
    }
}; 

此時成功將內容寫入指定路徑下文件中。

 

開發中是使用字節流好還是字符流好。

在所有的硬盤中保存文件或進行傳輸的時候,都是以字節的方式進行的,包括圖片,視頻等多媒體也是以字節進行

而字符是只有在內存中才會形成的,所以使用字節的時候是最多的

 

操作范例:文件拷貝

操作的時候可以按照如下格式進行:

java Copy 源文件 目標文件

如果要采用以上的格式,則肯定要使用初始化參數的形式,輸入兩個路徑。所以此時必須對輸入的參數個數進行驗證,判斷其是否為2

是使用字節流還是字符流呢,肯定使用字節流,因為萬一拷貝的是圖片呢?

要完成拷貝程序,有兩種方式:

實現一,將源文件中內容全部讀取進來,之后一次性寫入到目標文件。

實現二,邊讀邊寫。

很明顯第二種方式更好。

package 類集;
import java.io.* ;
public class Copy{
    public static void main(String args[]){
        if(args.length!=2){        // 判斷是否是兩個參數
            System.out.println("輸入的參數不正確。") ;
            System.out.println("例:java Copy 源文件路徑 目標文件路徑") ;
            System.exit(1) ; // 系統退出
        }
        File f1 = new File(args[0]) ;    // 源文件的File對象
        File f2 = new File(args[1]) ;    // 目標文件的File對象
        if(!f1.exists()){
            System.out.println("源文件不存在!") ;
            System.exit(1) ;
        }
        InputStream input = null ;        // 准備好輸入流對象,讀取源文件
        OutputStream out = null ;        // 准備好輸出流對象,寫入目標文件
        try{
            input = new FileInputStream(f1) ;
        }catch(FileNotFoundException e){
            e.printStackTrace() ;
        }
        try{
            out = new FileOutputStream(f2) ;
        }catch(FileNotFoundException e){
            e.printStackTrace() ;
        }
        if(input!=null && out!=null){    // 判斷輸入或輸出是否准備好
            int temp = 0 ; try{
                while((temp=input.read())!=-1){ // 開始拷貝 out.write(temp) ; // 邊讀邊寫
                }
                System.out.println("拷貝完成!") ;
            }catch(IOException e){
                e.printStackTrace() ;
                System.out.println("拷貝失敗!") ;
            }
            try{
                input.close() ; // 關閉 out.close() ; // 關閉
            }catch(IOException e){
                e.printStackTrace() ;
            }
        }
    }    
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM