1. 程式人生 > >Java實現檔案寫入——IO流(輸入輸出流詳解)

Java實現檔案寫入——IO流(輸入輸出流詳解)

輸入輸出的重要性:

     輸入和輸出功能是Java對程式處理資料能力的提高,Java以流的形式處理資料。流是一組有序的資料序列,根據操作的型別,分為輸入流和輸出流。

     程式從輸入流讀取資料,向輸出流寫入資料。Java是面向物件的程式語言,每一個數據流都是一個物件,它們提供了各種支援“讀入”與“寫入”操作的流類。

Java的輸入輸出功能來自java.io 包中的InputStream類、OutputStream類、Reader類和Writer類以及繼承它們的各種子類。

(一)解析檔案處理的奧祕

1、學習使用檔案類 : File類


     File類用於封裝系統的檔案和目錄的相關資訊。在該類中定義了一些與平臺無關的方法來操作檔案。例如檔案的大小、修改時間、檔案路徑等。

建立 File 物件可以通過下面3種方式:

方法1: 方法2: 方法3:
new File(String pathName) File file = new File(“E://1.txt”) new File(String parent , String child)
parent :父抽象路徑名;child:子路徑名字串

2、如何獲取檔案資訊

File 類是對檔案和資料夾的抽象,包含了對檔案和資料夾的多種屬性和操作方法。File類的常用方法如下表:

返回 方法 說明
String getName 獲取檔名稱
String getParent 獲取檔案的父路徑字串
String getPath 獲取檔案的相對路徑字串
String getAbsolutePath 獲取檔案的絕對路徑字串
boolean exists 判斷檔案或者資料夾是否存在
boolean isFile 判斷是不是檔案型別
boolean isDirectory 判斷是不是資料夾型別
boolean delete 刪除檔案或資料夾,如果刪除成功返回結果為true
boolean mkdir 建立資料夾,建立成功返回true
boolean setReadOnly 設定檔案或資料夾的只讀屬性
long length 獲取檔案的長度
long lastModified 獲取檔案的最後修改時間
String[ ] list 獲取資料夾中的檔案和子資料夾的名稱,並存放到字串陣列中

下面通過例項介紹File類獲取檔案資訊


package com.zch.io;

import java.io.File;
import java.util.Date;

/**
 * 在src根目錄下建立FileInfo類,在該類的主方法中建立檔案物件,通過File類的相關方法,獲取檔案的相關資訊
 * 
 * @author zch
 * 
 */
public class FileInfo {
    public static void main(String[] args) {

        String filePath = "src/com/zch/io/FileInfo.java";
        // 根據指定路徑建立檔案物件
        File file = new File(filePath);
        System.out.println("檔名稱:" + file.getName());
        System.out.println("檔案是否存在:" + file.exists());
        System.out.println("檔案的相對路徑:" + file.getPath());
        System.out.println("檔案的絕對路徑:" + file.getAbsolutePath());
        System.out.println("是否為可執行檔案:" + file.canExecute());
        System.out.println("檔案可以讀取:" + file.canRead());
        System.out.println("檔案可以寫入:" + file.canWrite());
        System.out.println("檔案上級路徑:" + file.getParent());
        System.out.println("檔案大小:" + file.length() + "B");
        System.out.println("檔案最後修改時間:" + new Date(file.lastModified()));
        System.out.println("是否檔案型別:" + file.isFile());
        System.out.println("是否為資料夾:" + file.isDirectory());

    }

}

執行結果如下:

檔名稱:FileInfo.java
檔案是否存在:true
檔案的相對路徑:src\com\zch\io\FileInfo.java
檔案的絕對路徑:D:\Java\IO\src\com\zch\io\FileInfo.java
是否為可執行檔案:true
檔案可以讀取:true
檔案可以寫入:true
檔案上級路徑:src\com\zch\io
檔案大小:1195B
檔案最後修改時間:Sat Sep 09 21:30:10 CST 2017
是否檔案型別:true
是否為資料夾:false

在使用delete()方法刪除File物件時,如果刪除的物件是目錄,該目錄中的內容必須為空。

(二)使用位元組輸入輸出流

     位元組流用於處理二進位制資料的讀取和寫入,它以位元組為單位,InputStream類和OutputStream類是位元組流的抽象類,它們定義了資料流讀取和寫入的基本方法。各個子類會依其特點實現或覆蓋這些方法。

1、位元組數入流抽象類InputStream

      InputStream 類是位元組輸入流的抽象類,定義了操作輸入流的各種方法,這些方法如表:

返回 方法 說明
int available() 返回當前輸入流的資料讀取方法可以讀取的有效位元組數量
Abstract int read() 從當前資料流中讀取一個位元組。若已達到流結尾,則返回-1
int read(byte[ ] bytes) 從當前輸入流讀取一定的byte資料,並存取在陣列中,然後返回讀取的byte資料的數量,若已到達流結尾,則返回-1。
void reset() 將當前的輸入流重新定位到最後一次呼叫mark()方法時的位置
void mark(int readlimit) 在當前輸入流中做標記位置,當呼叫reset()方法時將返回到該位置,從標記位置開始,到再讀入readlimit個字元為止,這個標記都維持有效。
Boolean markSupported() 測試當前輸入流是否支援mark()和reset()方法,只要其中一個不支援,則返回false
long skip(long n) 跳過和丟棄當前輸入的n個位元組資料
void close() 關閉當前輸入流,並釋放任何與之相關聯的系統資源

     InputStream 類是抽象類,不能通過new關鍵字來建立該例項物件,需要其子類建立該例項物件。下面通過例項如何使用InputStream從控制檯獲取使用者輸入的資料資訊。

package com.zch.io;

import java.io.IOException;
import java.io.InputStream;

/**
 * 建立InputStream例項inp,並將其賦值為System類的in屬性,定義為控制檯輸入流,從inp輸入流中獲取位元組資訊,
 * 用這些位元組資訊建立字串,並將其在控制檯上輸出。
 * @author zch
 *
 */
public class InputMessage {
    public static void main(String[] args) {
        InputStream inp = System.in;

        byte[] bytes = new byte[1024];

        try {
            while(inp.read() != -1){
                //根據使用者輸入的資訊建立字串

                String str = new String(bytes).trim();

            }
            inp.close();        //關閉流

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

2、位元組輸出流抽象類OutputStream類


OutputStream定義了輸出流的各種方法,如下表:

返回 方法 說明
void write(byte[ ] b) 將byte[ ] 陣列中的資料寫入當前輸出流
void write(byte[] b ,int off, int len) 將byte[ ]陣列下標off開始的len長度的資料寫入當前輸出流
Abstract void write(int b) 寫入一個byte資料到當前輸出流
void flush() 重新整理當前輸出流,並強制寫入所有緩衝的位元組資料
void close() 關閉當前輸出流

     和InputStream類一樣,OutputStream 類是抽象類,不能通過new關鍵字來建立該例項物件,需要其子類建立該例項物件。

package com.zch.io;

import java.io.IOException;
import java.io.OutputStream;

/**
 * 建立OutputStream例項out,並將其賦值為System.out標準輸出流。通過write()方法向流寫入資料。
 * @author zch
 *
 */
public class OutputData {
    public static void main(String[] args) {
    OutputStream output = System.out;           //例項化OutputStream物件

    byte[] bytes = "使用OutputStream輸出流在控制檯輸出字串\n".getBytes();       //建立bytes陣列

    try {
        output.write(bytes);

        bytes = "輸出內容:\n".getBytes();
        output.write(bytes);        //向流中寫入資料

        bytes = "Java資料互動管道——IO流 \n".getBytes();
        output.write(bytes);

        output.close();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
}

輸出結果如下:

使用OutputStream輸出流在控制檯輸出字串
輸出內容:
   Java資料互動管道——IO流 

3、檔案位元組輸入流類 : FileInputStream類


     檔案位元組輸入流可以從指定路徑的檔案中讀取位元組資料。檔案位元組輸入流類繼承InputStream類,並實現了讀取輸入流的各種方法。

       建立檔案位元組輸入流建立的構造方法語法如下:

  • 語法1:以File物件為引數建立FileInputStream例項
new FileInputStream(File file
  • 語法2:以檔案物件的絕對路徑為引數建立FIleInputStream例項
new FileInputStream(String filepath)

4、檔案位元組輸出流類:FileOutputStream

      檔案位元組輸出流關聯指定檔案路徑的檔案,資料通過檔案位元組輸出流以位元組為單位輸出並儲存到檔案中。檔案位元組輸出流繼承自OutputStream類,並實現OutputStream類的各種方法。

       檔案位元組輸出流的構造方法語法如下:

  • 語法1:以File物件為引數建立FileOutputStream例項
new FileOutputStream(File file
  • 語法2:以檔案物件的絕對路徑為引數建立FIleOutputStream例項
new FileOutputStream(String filepath)

下面通過例項介紹檔案的寫入和讀取:

package com.zch.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 建立OutputStream例項out,並將其賦值為System.out標準輸出流,通過write方法向流中寫入資料
 * 
 * @author zch
 * 
 */
public class FileCreate {
    public static void main(String[] args) {
        File file = new File("D:/", "word.txt");  //建立檔案物件

        try {
            if (!file.exists()) {               //如果檔案不存在則新建檔案
                file.createNewFile();           

            }
            FileOutputStream output = new FileOutputStream(file);

            byte[] bytes = "Java資料交流管道——IO流".getBytes();

            output.write(bytes);                //將陣列的資訊寫入檔案中

            output.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            FileInputStream input = new FileInputStream(file);

            byte[] bytes2 = new byte[1024];

            int len = input.read(bytes2);

            System.out.println("檔案中的資訊是:" + new String(bytes2, 0, len));

            input.close();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

(三) 使用字元輸入輸出流

      字元輸入輸出流 與 位元組輸入輸出流有相同的功能,但傳送資料的方式不一樣,位元組流以位元組為單位傳送資料,可以使任何型別的資料,例如文字、音訊、視訊、圖片等。字元流以字元為單位傳送資料,只能傳送文字型別的資料。使用字元輸入輸出流的好處是,當讀取中文時不會出現亂碼問題,而使用位元組輸入輸出流時,卻不能保證這一點。

1、字元輸入流抽象類:Reader類

該類定義了操作字元輸入流的方法,如下表:

返回 方法 說明
boolean ready() 判斷此資料流是否準備好
int read() 讀入一個字元,若已讀到流結尾,則返回值為-1
int read(char[ ]) 讀取一些字元到char[ ]陣列內,並返回所讀入的字元的數量,若已到達流結尾,則返回-1
Abscract int read(char[ ] chars,int off,int len) 讀取一些字元到char[ ]陣列下標從off開始到off+len的位置,並返回所讀入的字元的數量,若已到達流結尾,則返回-1;
void reset() 將當前輸入流重新定位到最後一次mark()方法時的位置
void mark(int readLimit) 將當前輸入流中做標記,當呼叫reset方法時將返回到該位置,從標記位置開始,到再讀入readLimit個字元為止,這個標記都維持有效
boolean markSupported 測試當前輸入流是否支援mark()方法和reset()方法。只要有一個方法不支援,則返回-1
long skip(long n) 跳過引數n指定的字元數量,並返回所跳過字元的數量
Abstract void close() 關閉字元輸入流,並釋放與之關聯的所有資源

2、字元輸出流類Writer類

       Writer 類主要是用於解決字元輸入流的類,其地位與Reader類在輸入流的地位和作用是相同的,也是所有字元輸出流的流類。

Writer類的主要方法如下:

返回 方法 說明
void write(char[ ] cbuf) 將字元陣列的資料寫入字元輸出流
Abstract void write(char[ ] cbuf int off ,int len) 將字元陣列從下標off 開始向輸入流寫入長度為len的資料
void write(int c ) 向字元輸入流中寫入一個字元資料
void write(String str ) 向輸入流中寫入一個字串資料
void write(String str , int off ,int len) 向輸入流中寫入一個字串從off 開始長度為len的資料
Abstract void flush() 重新整理當前輸出流,並強制寫入所有緩衝區的位元組資料
void close() 向輸出流中寫入緩衝區的資料,然後關閉當前輸出流,釋放所有與當前輸出流相關聯的系統資源

3、檔案字元輸入流FileReader

       檔案字元輸入流與檔案位元組輸入流的功能相似,但是傳送資料的方式不一樣,位元組流以位元組為單位傳送資料,可以使文字、視訊、音訊、圖片等。字元流以字元為單位傳送資料,只能傳送文字型別的資料。
建立字元輸入流常用的構造方法:

  • 語法1:
new FileReader(File file);
  • 語法2:
new FileReader(String path);

下面通過例項介紹FileReader類讀取指定磁碟檔案的內容。

package com.zch.io;

import java.io.File;
import java.io.FileReader;

public class FileInAndOut {
    public static void main(String[] args) {
        //定義指定磁碟的檔案的File物件
        File file = new File("D://word.txt");

        if(! file.exists()){
            System.out.println("對不起,不包含指定路徑的檔案");
        }else{
            //根據指定路徑的File物件建立FileReader物件
            try {
                FileReader fr = new FileReader(file);

                char[] data = new char[23];         //定義char陣列

                int length = 0;

                while((length = fr.read(data))>0){          //迴圈讀取檔案中的資料
                    String str = new String(data,0,length);         //根據讀取檔案的內容建立String 物件
                    System.out.println(str);                //輸出讀取內容
                }
                fr.close();                             //關閉流



            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }
}

執行結果如下圖:

這裡寫圖片描述
這裡寫圖片描述

4、檔案字元輸出流FileWriter

       檔案字元輸出流繼承自Writer類,提供了向檔案輸出的各種方法,資料通過檔案字元輸出流以字元為單位輸出並儲存到檔案中。

package com.zch.io;
/**
 * 通過給定的String型別引數的指定檔名稱與路徑,建立FileWriter類。
 * 
 * @author zch
 */
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {
    public static void main(String[] args) {
        File file = new File("D://word2.txt");      //建立指定檔案

        try {
        if(! file.exists()){
                file.createNewFile();               //如果指定檔案不存在,新建檔案

        }

        FileReader fr = new FileReader("D://word.txt");

        FileWriter fw = new FileWriter(file);               //建立FileWriter物件

        int length = 0;
        while((length = fr.read()) != -1){          //如果沒有讀到檔案末尾
            fw.write(length);           //向檔案寫入資料

        }
        fr.close();                         //關閉流
        fw.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

執行後建立了Word2.txt 檔案,並向其中寫入資料
這裡寫圖片描述

(四)IO流實戰:

1、Java IO流實現複製資料夾

       通過IO不僅可以複製檔案,還可以複製資料夾,但是資料夾內,可能包含其他資料夾,因此需要對他們進行分別複製。

package com.zch.io;

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

public class CopyFile {
    public static void main(String[] args) {
        File sourceFile = null;
        File desFile = null;

        String sourceFolder = "D://簡歷2";
        String copyFolder = "D://copy";

        sourceFile = new File(sourceFolder);

        if (!sourceFile.isDirectory() || !sourceFile.exists()) {
            System.out.println("原始檔夾不存在!");
        } else {
            desFile = new File(copyFolder);
            desFile.mkdir();

            copy(sourceFile.listFiles(), desFile);
            System.out.println("資料夾複製成功!");
        }
    }
/**
 * 建立copy方法,該方法接收檔案陣列和目標資料夾兩個引數,如果目標資料夾不存在,則呼叫mkdir()方法建立資料夾,然後再迴圈中將檔案陣列
 * 中的每個檔案物件寫到目標資料夾內。
 * @param fl
 * @param file
 */
    public static void copy(File[] fl, File file) {
        if (!file.exists()) { // 如果資料夾不存在
            file.mkdir(); // 建立新的資料夾
        }

        for (int i = 0; i < fl.length; i++) {
            if (fl[i].isFile()) { // 如果是檔案型別,則複製檔案
                try {
                    FileInputStream fis = new FileInputStream(fl[i]);
                    FileOutputStream out = new FileOutputStream(new File(
                            file.getPath() + File.separator + fl[i].getName()));

                    int count = fis.available();
                    byte[] data = new byte[count];

                    if ((fis.read(data)) != -1) {
                        out.write(data);
                    }
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

            if (fl[i].isDirectory()) { // 如果是資料夾型別
                File des = new File(file.getPath() + File.separator
                        + fl[i].getName());
                des.mkdir(); // 在目標資料夾中建立相同的資料夾
                copy(fl[i].listFiles(), des); // 遞迴呼叫方法本身
            }

        }

    }
}

執行本例項,會將D盤中的簡歷檔案中的內容複製到D盤的copy資料夾中,而且包含資料夾的子資料夾

2、Java IO流實現分行向檔案中寫入資料

      FileWriter類可以向檔案寫入字元資料,如果將FileWriter類封裝到BufferWriter類的緩衝字元流中,能夠實現緩衝字元輸出流,並且可以通過讀輸出流的newLine()方法,來實現資料的分行寫入。

package com.zch.io;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 建立BranchWriter類,在主方法中定義檔案物件,將該物件作為引數建立BufferedWriter類例項,
 * 呼叫該例項的writer方法將資料寫入檔案中,然後 呼叫newLine()方法寫入換行符,實現分行向檔案寫入資料。
 * 
 * @author zch
 * 
 */
public class BranchWriter {
    public static void main(String[] args) {
        String filePath = "D://BranchWriter.txt";

        File file = new File(filePath);

        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            FileWriter fw = new FileWriter(file); // 建立檔案輸出流

            BufferedWriter bw = new BufferedWriter(fw); // 使用緩衝區資料流封裝輸出流
            for (int i = 0; i < 100; i++) {             //迴圈寫入100行資料

                bw.write("Java互動管道——IO流".toCharArray());// 寫入資料到輸出流

                bw.newLine(); // 寫入換行符

                bw.flush(); // 重新整理緩衝區
            }

            System.out.println("成功寫入資料!");

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

3、刪除指定檔案

       File類的delete()方法可以實現刪除指定的檔案,首先使用目標檔案路徑建立File類的例項物件,然後再呼叫File類的delete()方法。

package com.zch.io;

import java.io.File;

public class FileDelete {

    public static void main(String[] args) {
        String filePath = "D://word.txt";

        File file = new File(filePath);
        delFile(file);
    }

    public static void delFile(File file) {
        if (!file.exists()) {
            System.out.println("檔案不存在!");
            return;
        }
        boolean rs = file.delete();
        if (rs) {
            System.out.println("檔案刪除成功!");
        } else {
            System.out.println("檔案刪除失敗!");
        }
    }
}