Java文件讀寫分析

本文內容:IO流操做文件的細節分析;分析各類操做文件的方式。java


讀寫一個文件

從一個示例開始分析,如何操做文件:數組

/**
 * 向一個文件中寫入數據
 * @throws IOException
 */
private static void writeFile() throws IOException {
    File file = new File("D://tmp/a.txt");
    try (OutputStream outputStream = new FileOutputStream(file, false)) {
        outputStream.write("ABC".getBytes(StandardCharsets.UTF_8));
    }
}

/**
 * 從一個文件中讀取數據
 * @throws IOException
 */
private static void readFile() throws IOException {
    File file = new File("D://tmp/a.txt");
    try (FileInputStream inputStream = new FileInputStream(file)) {
        StringBuilder stringBuffer = new StringBuilder();
        int count;
        while ((count = inputStream.read()) != -1) {
            stringBuffer.append((char) count);
        }
        System.out.println(stringBuffer.toString());
    }
}

文件寫入

向一個文件寫入數據時,首先新建一個文件,而後定義一個輸出流,爲何數輸出流?Java裏的API都是面向JVM的,輸入和輸出也是面向jvm的,輸入就是向jvm中輸入,輸出就是從jvm中輸出;
outputStream.write() 方法將一個字節數組寫入到a.txt中,執行完該方法後文件中就有內容了。程序是如何寫進去的?app

/**
 * Opens a file, with the specified name, for overwriting or appending.
 * @param name name of file to be opened
 * @param append whether the file is to be opened in append mode
 */
private native void open0(String name, boolean append)
    throws FileNotFoundException;

/**
 * Writes the specified byte to this file output stream.
 *
 * @param   b   the byte to be written.
 * @param   append   {@code true} if the write operation first
 *     advances the position to the end of file
 */
private native void write(int b, boolean append) throws IOException;

/**
 * Writes a sub array as a sequence of bytes.
 * @param b the data to be written
 * @param off the start offset in the data
 * @param len the number of bytes that are written
 * @param append {@code true} to first advance the position to the
 *     end of file
 * @exception IOException If an I/O error has occurred.
 */
private native void writeBytes(byte b[], int off, int len, boolean append)
    throws IOException;

private native void close0() throws IOException;

從源碼上看,文件寫入須要三個步驟:一、打開一個文件,也就是獲取文件的句柄;二、向文件中輸出字節流;三、關閉輸出流,釋放資源;
open0(String name, boolean append) 這個本地方法就是打開文件的方法,調用了操做系統的API。
write(int b, boolean append)這個本地方法是最終的寫入的方法,參數有兩個:b[],append; b表明的是一個字節數組,append表明是否添加,false則會覆蓋初始文件。jvm

文件讀取

與寫入文件相似,文件讀取一樣也是相對與jvm,文件讀取是向jvm中輸入,因此是InputStream;ui

private native int read0() throws IOException;

/**
 * Reads a subarray as a sequence of bytes.
 * @param b the data to be written
 * @param off the start offset in the data
 * @param len the number of bytes that are written
 * @exception IOException If an I/O error has occurred.
 */
private native int readBytes(byte b[], int off, int len) throws IOException;

讀取文件也是兩種方法,一個字節一個字節地讀,也能安裝字節數組去讀。步驟與文件寫入相似:一、打開一個文件,也就是獲取文件的句柄;二、從文件中讀取字節流;三、關閉輸入流,釋放資源;this

細節分析

字節數組讀寫的問題

按照字節寫入,是直接調用native方法獲取文件句柄操做文件,而且是直接寫入字節數組,可是若是是寫入中文,就不同了,UTF-8編碼中漢字是3個字節,英文字母是1個字節;固然不一樣的編碼方式還不同。這樣寫入不會有問題,可是讀取的時候,問題就來了,漢字是3個字節,無論是按照字節數組仍是字節去讀,均可能只讀取了一個漢字的一半,這樣讀取出來的字節數組轉成可視化的內容就會出現亂碼。編碼

若是是從一個輸入流到另一個輸出流,好比文件導出,就可使用輸入流讀取的字節數組直接放到輸出流中去。注意:讀取到文件最後會返回-1,能夠以此爲分界點。操作系統

private static void writeFile0() throws IOException {
    File fileA = new File("D://tmp/a.txt");
    File fileB = new File("D://tmp/b.txt");
    try (FileInputStream inputStream = new FileInputStream(fileA);
         OutputStream outputStream = new FileOutputStream(fileB)) {
        int count;
        byte[] bytes = new byte[64];
        while ((count = inputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, count);
        }
    }
}

按照字符讀取

在Java API中提供了另一種方式操做文件,那就是按照字符讀取,也能按行讀取。這種讀取方式在文件和jvm中間加了一層緩衝區。code

private static void readFile1() throws IOException {
    File file = new File("D://tmp/a.txt");
    try (FileReader fileReader = new FileReader(file)) {
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        int count;
        StringBuilder stringBuilder = new StringBuilder();
        while ((count = bufferedReader.read()) != -1) {
            // 還能夠按行讀取bufferedReader.readLine();
            stringBuilder.append((char) count);
        }
        System.out.println(stringBuilder.toString());
    }
}
相關文章
相關標籤/搜索