Java文件IO流的操作總結


Java中的IO操作涉及到的概念及相關類很多,很容易弄混,今天特來整理總結一下,並附上一份完整的文件操作的代碼。

概念解析

讀和寫

流就是管道,向管道里面寫數據用輸出流:write
從管道里面讀數據,用輸入流:read

流的分類

流,按照不同的維度有不同的分類,按照從流中每次讀取數據單位不同,划分為字節流字符流。
按照流-對應操作的角色的不同(是IO設備,還是其他流)是否能夠直接向特定的IO設備如文件、網絡、磁盤等,能夠直接與這些進行讀寫的稱之為節點流,
對節點流進一步封裝的流,通過封裝后的流來實現讀寫功能,處理流也被稱為高級流。 

注意事項

1、流和數組不一樣,不能通過索引讀寫數據。在流中,你也不能像數組那樣前后移動讀取數據,除非使用RandomAccessFile 處理文件。
2、流僅僅只是一個連續的數據流。流中的數據只能夠順序訪問。當達到流末尾時,返回-1。
3、InputStream的read()方法返回一個字節大小,返回值的范圍在0到255之間。
4、Reader的read()方法返回一個字符,會根據文本的編碼,一次讀取一個或者多個字節,返回值的范圍在0到65535之間。
5、read(byte[])會嘗試讀取與給定字節數組容量一樣大的字節數,返回值int表示已經讀取過的字節數。如果InputStream內可讀的數據不足以填滿字節數組,那么數組剩余的部分將包含本次讀取之前的數據。記得檢查有多少數據實際被寫入到了字節數組中。
6、read(byte, int offset, int length)同樣將數據讀取到字節數組中,不同的是,該方法從數組的offset位置開始,並且最多將length個字節寫入到數組中。同樣地,read(byte, int offset, int length)方法返回一個int變量,表示有多少字節已經被寫入到字節數組中,所以請記得在讀取數據前檢查上一次調用read(byte, int offset, int length)的返回值。

示例代碼

package com.lingyejun.io;

import java.io.*;

/**
 * Created by Lingye on 2018/9/27 20:15
 */
public class FileStreamOperate {

    public static final String READ_UTF8_FILE_PATH = "D:\\input-utf8.txt";
    public static final String READ_UNICODE_FILE_PATH = "D:\\input-unicode.txt";
    public static final String WRITE_BYTES_FILE_PATH = "D:\\output-bytes.txt";
    public static final String WRITE_CHARS_FILE_PATH = "D:\\output-char.txt";


    /**
     * 按照字節流的方式讀取文件內容
     *
     * Step 1.根據文件路徑,構建文件對象
     * Step 2.創建輸入流用來讀取文件內容
     * Step 3.創建字節數組來存放讀取內容
     * Step 4.關閉讀取文件的輸入流
     *
     * @return
     */
    public void readFileByFileInputStream() {
        System.out.println("=== readFileByFileInputStream Start ===");
        // 構建文件對象
        File inputFile = new File(READ_UTF8_FILE_PATH);
        // 初始化輸入流
        InputStream inputStream = null;
        try {
            // 創建字節輸入流
            inputStream = new FileInputStream(inputFile);
            // 讀取到1KB字節數組中
            byte[] buffer = new byte[100];
            // 每次讀取的字節數
            int readLength;
            // 讀取數據並放到buffer數組中
            while ((readLength = inputStream.read(buffer)) != -1) {
                // UTF-8為變長編碼,一個漢字占3個字節
                System.out.println("本次讀取" + readLength + "個字節數據內容為:" + new String(buffer));
            }
        } catch (FileNotFoundException e) {
            // 文件未找到時異常處理
            e.printStackTrace();
        } catch (IOException e) {
            // 讀取過程中,刪除文件會出此異常
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 關閉流過程,也有可能出現異常
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== readFileByFileInputStream End ===");
    }

    /**
     * 按照字符流的方式讀取文件內容
     *
     * Step 1.根據文件路徑,構建文件對象
     * Step 2.創建字符輸入流讀取文件內容
     * Step 3.創建字符數組來存放讀取內容
     * Step 4.關閉讀取文件的字符輸入流
     *
     * @return
     */
    public void readFileByFileReader(){
        System.out.println("=== readFileByFileReader Start ===");
        // 根據路徑拿到文件對象
        File file = new File(READ_UTF8_FILE_PATH);
        // 初始化字符輸入流
        Reader fileReader = null;
        // 初始化存放讀取內容的字符數組
        char[] charArray = new char[100];
        // 初始化一個字符
        char once;
        try {
            fileReader = new FileReader(file);
            // 一次讀取一個數組長度的字符串
            fileReader.read(charArray);
            System.out.println(charArray);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null) {
                try {
                    // 關閉流過程,也有可能出現異常
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== readFileByFileReader End ===");
    }

    /**
     * 通過字節流的方式寫入信息到文件
     *
     * Step 1.根據文件路徑,構建文件對象
     * Step 2.創建字節輸出流寫出信息到文件
     * Step 3.構造待寫出的內容,並轉為字節數組
     * Step 4.關閉讀取文件的字符輸出流
     */
    public void writeFileByFileOutputStream() {
        System.out.println("=== writeFileByFileOutputStream Start ===");
        // 創建寫出文件
        File file = new File(WRITE_BYTES_FILE_PATH);
        // 初始化字節輸出流
        OutputStream outputStream = null;
        // 寫出內容
        String outInfo = "寫出測試";
        // 轉成字節數組
        byte[] byteArray = outInfo.getBytes();
        try {
            // 創建輸出字節流
            outputStream = new FileOutputStream(file);
            outputStream.write(byteArray);
            System.out.println("按照字節流成功寫出內容:"+outInfo);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    // 關閉寫出流時,注意抓異常
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== writeFileByFileOutputStream End ===");
    }

    /**
     * 通過字符流的方式寫入信息到文件
     *
     * Step 1.根據文件路徑,構建文件對象
     * Step 2.創建字符輸出流寫出信息到文件
     * Step 3.構造待寫出的內容,並轉為字符數組
     * Step 4.關閉讀取文件的字符輸出流
     */
    public void writeFileByFileWriter(){
        System.out.println("=== writeFileByFileWriter Start ===");
        // 創建寫出文件
        File file = new File(WRITE_CHARS_FILE_PATH);
        // 初始化字符輸出流
        Writer fileWriter = null;
        String strInfo = "字符寫出數據";
        try {
            // 創建輸出字符流
            fileWriter = new FileWriter(file);
            // 寫出內容
            fileWriter.write(strInfo);
            System.out.println("按照字符流成功寫出內容:"+strInfo);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fileWriter != null){
                try {
                    // 關閉寫出流時,注意抓異常
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("=== writeFileByFileWriter End ===");
    }

    /**
     * 任意讀取文件內容
     */
    public void randomAccessFile(){
        System.out.println("=== randomAccessFile Start ===");
        File file = new File(READ_UTF8_FILE_PATH);
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"r");
            // 獲取文件當前的指針位置
            System.out.println("file now pointer is "+randomAccessFile.getFilePointer());
            // 將文件指針設置到指定位置(絕對位置)
            randomAccessFile.seek(3);
            // 相對位置,相對於當前的位置,
            randomAccessFile.skipBytes(3);
            System.out.println("file now pointer is "+randomAccessFile.getFilePointer());
            // 字節數組
            byte[] buffer = new byte[17];
            // off是指的寫到buffer的數組的起始位置
            randomAccessFile.read(buffer,0,buffer.length);
            System.out.println(new String(buffer));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("=== randomAccessFile End ===");
    }

    /**
     * 通過字節流的方式將文件內容拷貝到另一個文件中
     *
     * Step 1.根據文件路徑,構建源文件對象
     * Step 2.根據文件路徑,構造目的文件對象
     * Step 3.創建字節輸入流從源文件中讀取信息
     * Step 4.將讀入到內存的信息再寫出到目的文件中
     * Step 5.拷貝完成后關閉輸入輸出流
     */
    public void copyFile() {
        System.out.println("=== copyFile Start ===");
        // 輸入文件對象
        File inFile = new File(READ_UTF8_FILE_PATH);
        // 輸出文件對象
        File outFile = new File(WRITE_BYTES_FILE_PATH);
        // 初始化輸入流
        InputStream inputStream = null;
        // 初始化輸出流
        OutputStream outputStream = null;
        try {
            // 將輸入流懟到輸入文件,使程序內存與磁盤建立聯系
            inputStream = new FileInputStream(inFile);
            // 將輸出流懟到輸出文件,使程序內存與磁盤建立聯系
            outputStream = new FileOutputStream(outFile);
            while (true) {
                // 讀取信息到內存
                int temp = inputStream.read();
                // 拷貝完成
                if (temp == -1) {
                    break;
                }
                // 將內容拷貝到輸出文件中
                outputStream.write(temp);
            }
            System.out.println("拷貝文件成功完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 關閉輸入流異常后,也要保證輸出流關閉
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        System.out.println("=== copyFile End ===");
    }

    public static void main(String[] args) {
        FileStreamOperate fileStreamOperate = new FileStreamOperate();
        // 按照字節流讀取的話,一個漢字兩個字節
        fileStreamOperate.readFileByFileInputStream();
        // 按照字符讀取,java Unicode編碼一個字符(不論字母還是漢字)兩個字節
        fileStreamOperate.readFileByFileReader();
        // 采用任意讀取的方式讀取文件信息
        fileStreamOperate.randomAccessFile();
        // 按照字節流的方式寫信息到文件
        fileStreamOperate.writeFileByFileOutputStream();
        // 按照字符流的方式寫信息到文件
        fileStreamOperate.writeFileByFileWriter();
        // 拷貝文件
        fileStreamOperate.copyFile();
    }
}  

輸入輸出文件和執行結果

文件展示

執行結果

小結

通過本篇,我們學會了文件IO的一些常規操作方式,但是每次讀取完文件后都需要在最后進行關閉流資源的close操作,這個操作不可省略,但是每次都寫又顯得十分啰嗦,有沒有更加簡便的方式呢,請看我的下一篇文章《try with resources簡潔的異常捕獲機制》。 

 

參考文章:https://blog.csdn.net/yhl_jxy/article/details/79272792


免責聲明!

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



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