1. 程式人生 > >Java IO流常用操作方法總結

Java IO流常用操作方法總結

一、簡介

在實際工作中,基本上每個專案難免都會有檔案相關的操作,比如檔案上傳、檔案下載等,這些操作都是使用IO流進行操作的,本文將通過簡單的示例對常用的一些IO流進行總結。

二、使用詳解

【a】FileInputStream與FileOutputStream

首先通過檢視jdk文件,瞭解下FileInputStream與FileOutputStream的操作方法:

FileInputStream:

FileOutputStream:

輸入流主要是通過read讀取檔案,輸出流主要是通過write寫出到檔案。

下面以檔案拷貝的示例說明FileinputStream與FileOutputStream的使用方法:

public class CopyFileUtils {

    /**
     *
     * @param sourceFile
     * @param destFile
     * @throws IOException
     */
    public static void copyFile(File sourceFile, File destFile) throws IOException {
        //1. 原始檔必須存在並且是檔案
        if (!sourceFile.exists() || !sourceFile.isFile()) {
            System.out.println("原始檔必須存在並且是檔案");
            return;
        }

        if (destFile.isDirectory()) {
            return;
        }

        //2. 建立與檔案的聯絡
        InputStream is = new FileInputStream(sourceFile);
        OutputStream os = new FileOutputStream(destFile);
        //實際接收長度
        int len = 0;
        //緩衝位元組陣列
        byte[] buffer = new byte[1024];
        //3. 迴圈讀取檔案
        while ((len = is.read(buffer)) != -1) {
            //4. 通過OutputStream寫出到檔案
            os.write(buffer, 0, len);
        }
        // 5. 關閉流
        os.flush();
        os.close();
        is.close();
    }

    public static void copyFile(String sourcePath, String destPath) throws IOException {
        //1. 原始檔、目標檔案建立聯絡
        File sourceFile = new File(sourcePath);
        File destFile = new File(destPath);
        copyFile(sourceFile, destFile);
    }

}

測試:

public class TestCopyFileUtils {

    public static void main(String[] args) {
        try {
            CopyFileUtils.copyFile("d:/aaa/a.txt", "d:/aaa/b.txt");
        } catch (IOException e) {
            System.out.println("檔案拷貝失敗!");
            e.printStackTrace();
        }
    }

}

執行結果:

下面以資料夾拷貝的示例來鞏固FileinputStream與FileOutputStream的使用方法:

public class CopyDirUtils {

    public static void copyDir(String sourcePath, String destPath) throws IOException {
        //1. 建立與檔案的聯絡
        File sourceFile = new File(sourcePath);
        File destFile = new File(destPath);
        //如果原始檔是一個資料夾
        if (sourceFile.isDirectory()) {
            destFile = new File(destFile, sourceFile.getName());
        }
        copyDirDetail(sourceFile, destFile);
    }

    private static void copyDirDetail(File sourceFile, File destFile) throws IOException {
        //2. 如果原始檔是一個檔案,則直接拷貝即可
        if (sourceFile.isFile()) {
            //拷貝檔案
            CopyFileUtils.copyFile(sourceFile, destFile);
        } else if (sourceFile.isDirectory()) {
            //3. 如果原始檔是一個資料夾,那麼需要確保目標資料夾存在
            destFile.mkdirs();
            //4. 使用listFiles遞迴呼叫copyDirDetail拷貝資料夾以及子檔案
            for (File subFile : sourceFile.listFiles()) {
                copyDirDetail(subFile, new File(destFile, subFile.getName()));
            }
        }
    }

}

測試:

public class TestCopyDirUtils {

    public static void main(String[] args) throws IOException {
        String sourcePath = "d:/aaa";
        String destPath = "d:/bbb";
        CopyDirUtils.copyDir(sourcePath, destPath);
    }

}

執行結果:

 

【b】FileReader與FileWriter

FileReader與FileWriter並沒有新增的方法,跟上面的用法基本類似,只是FileReader與FileWriter只能讀取純文字的檔案。

下面分別講解FileReader與FileWriter的基礎用法:

/**
 * @Description: 純文字讀取
 * @Author: weishihuai
 * @Date: 2018/11/1 20:40
 */
public class FileReaderAndFileWriter {

    public static void main(String[] args) {
        //先寫內容到檔案
        writeFile();
        //再讀取出來
        readFile();
    }

    /**
     * 把內容輸出到檔案
     */
    public static void writeFile() {
        //1. 需要寫出的目標檔案路徑
        File file = new File("d:/aaa/b.txt");
        Writer writer = null;

        try {
            //2. 建立與目標檔案的聯絡
            writer = new FileWriter(file);
            //3. 使用write()直接寫出字串(只能寫出純文字內容)
            writer.write("hello world!!!!!!!!!");
            //4. 重新整理流
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5. 關閉流
            if (null != writer) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 讀取檔案中的內容
     */
    public static void readFile() {
        //1. 定義原始檔路徑
        File file = new File("d:/aaa/b.txt");
        Reader reader = null;

        try {
            //2. 建立與原始檔的聯絡
            reader = new FileReader(file);
            //3. 字元快取陣列
            char[] buffer = new char[1024];
            //4. 定義實際接收長度
            int len = 0;
            //5. 迴圈讀取檔案內容
            while (-1 != (len = reader.read(buffer))) {
                System.out.println(new String(buffer));
            }

        } catch (java.io.IOException e) {
            e.printStackTrace();
            System.out.println("原始檔讀取失敗");
        } finally {
            //6. 關閉流
            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("關閉流失敗");
                }
            }
        }
    }

}

執行結果:

 

【c】BufferedInputStream與BufferedOutStream

BufferedInputStream與BufferedOutStream是位元組處理流,起到增強功能, 提高效能的作用。(推薦使用)

BufferedInputStream與BufferedOutStream的使用方法並沒有太大區別,只是在原來FileInputStream與FileOutputStream的外層包裹一個處理流BufferInputStream與BufferOutStream而已,使用方法如下:

/**
 * @Description: 位元組處理流(增強功能, 提高效能, 處理流一定要在節點流之上)
 * @Author: weishihuai
 * @Date: 2018/11/1 20:56
 */
public class BufferInputStreamAndBufferOutStream {

    public static void main(String[] args) {
        //1.建立與原始檔、目標檔案的聯絡
        File sourceFile = new File("d:/aaa/a.txt");
        File destFile = new File("d:/aaa/aa.txt");

        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            //在外層包裹一層處理流,加強功能
            inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
            outputStream = new BufferedOutputStream(new FileOutputStream(destFile));
            //2. 定義緩衝位元組陣列以及實際接收長度len
            byte[] buffer = new byte[1024];
            int len = 0;
            //3. 迴圈讀取檔案中的內容
            while (-1 != (len = inputStream.read(buffer))) {
                //4.通過write將讀取的內容寫出到檔案中
                outputStream.write(buffer, 0, len);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5. 關閉流
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

執行結果:

 

【d】BufferedReader與BufferedWriter

新增方法如下,其他方法都是從Reader或者Writer繼承過來

BufferedReader:readLine() 讀取一個文字行。

BufferedWriter:newLine() 寫入一個行分隔符。

下面還是通過一個簡單的示例講解BufferedReader與BufferedWriter的使用方法:

public class BufferReaderAndBufferWriter {

    public static void main(String[] args) {
        //1. 建立與原始檔、目標檔案的聯絡
        File sourceFile = new File("d:/aaa/a.txt");
        File destFile = new File("d:/aaa/c.txt");

        BufferedReader reader = null;
        BufferedWriter writer = null;

        try {
            //2. 使用BufferedReader和BufferedWriter包裹FileReader和FileWriter
            //注意: 只能讀取純文字檔案
            reader = new BufferedReader(new FileReader(sourceFile));
            writer = new BufferedWriter(new FileWriter(destFile));

            //3. 定義實際接收的字串
            String str;

            //4. 使用reader.readLine()一行一行迴圈讀取
            while (null != (str = reader.readLine())) {
                //5. 使用write()直接寫出字串到檔案c.txt
                writer.write(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //6. 關閉流
            if (null != writer) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != reader) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

執行結果:

 

【e】InputStreamReader與OutputStreamWriter

轉換流,主要用於解決檔案讀取或者寫入出現的亂碼問題。

出現亂碼的問題一般有兩種:

(1) 編碼與解碼的字符集不統一

(2) 位元組數不夠,長度丟失

下面我們通過示例講解怎麼解決亂碼問題:

/**
 * @Description: 轉換流(位元組流 轉換為 字元流)
 * @Author: weishihuai
 * @Date: 2018/11/1 21:22
 * <p>
 * 轉換流: 主要用於解決亂碼問題(保證原始檔的編碼集已知)
 */
public class InputStreamReaderAndOutputStreamWriter {

    public static void main(String[] args) throws IOException {
        //1. 指定解碼字符集
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("d:/aaa/c.txt")), "utf-8"));
        //2. 定義實際接收字串
        String string;
        //3. 一行一行讀取純文字檔案內容
        while (null != (string = reader.readLine())) {
            System.out.println(string);
        }
    }

}

如圖,我們檔案的編碼為ANSI編碼,我們指定的解碼字符集為UTF-8,執行結果:

下面我們修改一下c.txt的編碼字符集為UTF-8,再次執行程式,

如圖,通過指定相同的編碼與解碼字符集,亂碼問題就解決了。

【f】ByteArrayInputStream與ByteArrayOutputStream

ByteArrayInputStream與ByteArrayOutputStream是位元組陣列輸入輸出流,主要是將位元組陣列輸出到檔案中,再通過讀取檔案中的位元組陣列將內容讀取出來。

/**
 * @Description: 位元組陣列流 位元組流
 * @Author: weishihuai
 * @Date: 2018/11/2 20:43
 */
public class ByteArrayInputStreamAndByteArrayOutputStream {

    public static void read(byte[] bytes) {
        ByteArrayInputStream bis = null;
        //1. 實際接收長度
        int len = 0;
        //位元組陣列
        byte[] bytes1 = new byte[1024];
        try {
            //2. 建立位元組陣列輸入流
            bis = new ByteArrayInputStream(bytes);
            //3. 迴圈將檔案中的位元組陣列讀取出來
            while (-1 != (len = bis.read(bytes1))) {
                System.out.println(new String(bytes1));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 關閉流
            if (null != bis) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static byte[] write() {
        //位元組陣列
        byte[] dest;
        String string = "位元組陣列流 位元組流 節點流";
        //需要寫入檔案的位元組陣列
        byte[] bytes = string.getBytes();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //使用write將位元組陣列寫入到檔案中
        bos.write(bytes, 0, bytes.length);
        //使用toByteArray()將輸出流轉化為位元組陣列
        dest = bos.toByteArray();
        return dest;
    }

    public static void main(String[] args) {
//        read();
        read(write());
    }

}

執行結果:

下面通過示例講解位元組陣列流與檔案流對接:

/**
 * @Description: 位元組陣列流與檔案流對接
 * @Author: weishihuai
 * @Date: 2018/11/2 20:57
 */
public class ByteArrayToStream {

    public static void main(String[] args) {
        byte[] bytes = getBytesFromFile("d:aaa/a.txt");
        System.out.println(new String(bytes));
        toFileFromByteArray(bytes, "d:/aaa/t.txt");
    }

    /**
     * 從檔案中讀取到位元組陣列流中(檔案輸入流讀取檔案/位元組陣列輸出流將檔案寫出到位元組陣列)
     *
     * @param sourcePath 原始檔路徑
     * @return
     */
    public static byte[] getBytesFromFile(String sourcePath) {
        File sourceFile = new File(sourcePath);
        byte[] dest;
        InputStream is = null;
        ByteArrayOutputStream bos = null;
        try {
            is = new BufferedInputStream(new FileInputStream(sourceFile));
            bos = new ByteArrayOutputStream();

            int len = 0;
            byte[] buffer = new byte[1024];
            while (-1 != (len = is.read(buffer))) {
                bos.write(buffer, 0, buffer.length);
            }
            bos.flush();
            dest = bos.toByteArray();
            return dest;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != bos) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 位元組陣列輸出到檔案(位元組陣列輸入流將位元組陣列讀取出來/檔案輸出流將位元組陣列寫出到檔案儲存)
     *
     * @param bytes 位元組陣列
     */
    public static void toFileFromByteArray(byte[] bytes, String destPath) {
        OutputStream os = null;
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        int len = 0;
        byte[] buffer = new byte[1024];
        try {
            os = new FileOutputStream(new File(destPath));
            while (-1 != (len = bis.read(buffer))) {
                os.write(buffer, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != bis) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}

執行結果:

三、總結

以上是工作中常用的IO流操作檔案的方法,具體可以根據實際情況進行調整,本文是筆者在複習IO操作方法的一些總結,僅供大家學習參考,大家可以進行進一步優化,一起學習一起進步。