一文帶你入門Java之I/O流

一、IO流的概述

1. 流的類型

  1. 操作數據單位:字節流、字符流
  2. 數據的流向:輸入流、輸出流
  3. 流的角色:節點流、處理流
    圖解
    以字體顏色劃分類別
    在這裏插入圖片描述

2. 體系結構

重點學習藍色框中的內容
在這裏插入圖片描述

3. 輸入、輸出的基本步驟

輸入過程

  1. 創建File類的對象,指明讀取的數據的來源。(要求此文件一定要存在)
  2. 創建相應的輸入流,將File類的對象作爲參數,傳入流的構造器中
  3. 具體的讀入過程: 創建相應的byte[] 或 char[]。
  4. 關閉流資源
    說明:程序中出現的異常需要使用try-catch-finally處理。

輸出過程

  1. 創建File類的對象,指明寫出的數據的位置。(不要求此文件一定要存在)
  2. 創建相應的輸出流,將File類的對象作爲參數,傳入流的構造器中
  3. 具體的寫出過程: write(char[]/byte[] buffer,0,len)
  4. 關閉流資源
    說明:程序中出現的異常應使用try-catch-finally處理。

二、字符流

字符流只能處理文本文件(例如:.txt,.java,.c,.cpp)。

1. 字符輸入流

@Test public void testFileReader() {
        FileReader fr = null;

        try {
            //1. File的實例化
            File file = new File("testFileReader.txt");
            //2. 實例化 FileReader流
            fr = new FileReader(file);
            //3. 進行讀入操作
            //read(char[] charbuffer):返回每次讀入到數組中的字符個數,若達到文件末尾則返回-1
            char[] charbuffer = new char[5];
            int len;
            while ((len = fr.read(charbuffer)) != -1) {
                //方式一:
                //for (int i = 0; i < len; i++) {
                //    System.out.print(charbuffer[i]);
                //}
                //方式二:
                String str = new String(charbuffer, 0, len);
                System.out.print(str);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //4. 流的關閉
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

2. 字符輸出流

@Test public void testFileWriter() {
        //1. File的實例化
        File file = new File("testFileWriter.txt");
        FileWriter fw = null;
        try {
            //2. FileWriter
            fw = new FileWriter(file);
            //3. 進行寫出操作
            fw.write("Hello, ");
            fw.write("world ! ");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4. 流的關閉
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

三、字節流

字節流可處理所有文件

字節輸入流/字節輸出流

運用兩種字節流進行文件複製操作

public void fileInputOutputStreamTest() throws IOException {
        //1. 創建File類對象,指定讀入與寫出的文件
        File srcFile = new File("img1.jpg");
        File destFile = new File("copy.jpg");
        //2. 創建輸入輸出流
        FileInputStream fileInputStream = new FileInputStream(srcFile);
        FileOutputStream fileOutputStream = new FileOutputStream(destFile);
        //3. 數據的讀入與寫出操作
        byte[] buffer = new byte[1024];
        //記錄字符個數
        int len;
        while ((len = fileInputStream.read(buffer)) != -1) {
            //每次寫出len個字符
            fileOutputStream.write(buffer, 0, len);
        }
        //4.關閉流 - 建議從後向前關閉流
        fileOutputStream.close();
        fileInputStream.close();
    }

四、緩衝流

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWriter

緩衝流作用:提供流的讀取、寫入的速度
提高讀寫速度的原因:內部提供了一個緩衝區。默認情況下是8kb
在這裏插入圖片描述

1. 字符緩衝流

 @Test
    public void testBufferedReaderWriter() throws IOException {
        //1.實例化文件和流
        BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new File("copy.txt")));
        //2.進行數據讀寫
        char[] charbuffer = new char[1024];
        int len;
        while((len = br.read(charbuffer)) != -1){
            bw.write(charbuffer,0,len);
        }
        //3. 關閉資源
        bw.close();
        br.close();

    }

2. 字節緩衝流

 @Test
    public void copyFileWithBuffered() throws IOException {
        //1. 創建File類對象,指定讀入與寫出的文件
        File srcFile = new File("img1.jpg");
        File destFile = new File("copy.jpg");
        //2. 創建輸入輸出流
        InputStream fileInputStream = new FileInputStream(srcFile);
        FileOutputStream fileOutputStream = new FileOutputStream(destFile);
        //3. 創建緩衝流
        BufferedInputStream bis = new BufferedInputStream(fileInputStream);
        BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
        //4. 數據的讀入與寫出操作
        byte[] buffer = new byte[1024];
        //記錄字符個數
        int len;
        while ((len = fileInputStream.read(buffer)) != -1) {
            //每次寫出len個字符
            bos.write(buffer, 0, len);
        }
        //5.關閉流 - 建議從後向前關閉流
        bos.close();
        bis.close();
    }

五、字符轉換流

由於字符存在編碼問題,轉換流用於解決字符轉碼問題。

1. 輸入字符轉換流

@Test public void inputStreamReaderTest() throws IOException {

        FileInputStream fis = new FileInputStream("hello.txt");
        //InputStreamReader isr = new InputStreamReader(fis);//使用系統默認的字符集
        //參數2指明瞭字符集,具體使用哪個字符集,取決於文件dbcp.txt保存時使用的字符集
        //使用系統默認的字符集 默認爲 UTF-8
        InputStreamReader isr = new InputStreamReader(fis, "UTF-8");

        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1) {
            String str = new String(cbuf, 0, len);
            System.out.print(str);
        }
        isr.close();
    }

2. 輸出字符轉換流

該例子爲綜合輸入和輸出字符轉換流

@Test 
public void outputStreamWriterTest() throws Exception {
        //1.造文件、造流
        File file1 = new File("hello.txt");
        File file2 = new File("hello_gbk.txt");

        FileInputStream fis = new FileInputStream(file1);
        FileOutputStream fos = new FileOutputStream(file2);

        InputStreamReader isr = new InputStreamReader(fis, "utf-8");
        OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk");

        //2.讀寫過程
        char[] cbuf = new char[20];
        int len;
        while ((len = isr.read(cbuf)) != -1) {
            osw.write(cbuf, 0, len);
        }

        //3.關閉資源
        isr.close();
        osw.close();

    }

六、對象流

自定義類型的對象使用對象流的條件:

  1. 需要實現接口:Serializable
  2. 當前類提供一個全局常量:serialVersionUID
  3. 除了當前類需要實現Serializable接口之外,還必須保證其內部所屬性也必須是可序列化的。(默認情況下,基本數據類型可序列化)

補充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量

import org.junit.Test;
import java.io.*;

public class ObjectInputOutputStreamTest {

	/**
     * 對象輸出流
     */
    @Test 
    public void objectOutputStreamTest() {
        ObjectOutputStream oos = null;

        try {
            //1.
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
            //2.
            oos.writeObject(new String("I like Java"));
            oos.flush();//刷新操作

            oos.writeObject(new Student("張三", 23));
            oos.flush();

            oos.writeObject(new Student("李四", 23, 1001));
            oos.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                //3.
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }
	/**
     * 對象輸入流
     */
    @Test 
    public void objectInputStreamTest() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("object.dat"));

            Object obj = ois.readObject();
            String str = (String)obj;

            Student student = (Student)ois.readObject();
            Student student1 = (Student)ois.readObject();

            System.out.println(str);
            System.out.println(student);
            System.out.println(student1);

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

            }
        }
    }
}
//實體類/自定義類型
class Student implements Serializable{

    private static final long serialVersionUID = -121294470754667710L;
    
    private String name;
    private int age;
    private int score;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override public String toString() {
        return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + '}';
    }
}

七、RandomAccessFile/隨機存取文件流

  1. RandomAccessFile直接繼承於java.lang.Object類,實現了DataInput和DataOutput接口。
  2. RandomAccessFile既可以作爲一個輸入流,又可以作爲一個輸出流
  3. 如果RandomAccessFile作爲輸出流時,寫出到的文件如果不存在,則在執行過程中自動創建。
    如果寫出到的文件存在,則會對原文件內容進行覆蓋。(默認情況下,從頭覆蓋)
  4. 可以通過seek(int pos) ,實現RandomAccessFile插入數據的效果。
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileTest {

    /**
     * 實現複製粘貼
     * @throws IOException
     */
    @Test public void randomAccessFileTest1() throws IOException {

        //1.創建流
        RandomAccessFile raf1 = new RandomAccessFile(new File("img.jpg"), "r");
        RandomAccessFile raf2 = new RandomAccessFile(new File("img1.jpg"), "rw");
        //2.創建緩衝區
        byte[] buffer = new byte[1024];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            raf2.write(buffer, 0, len);
        }
        //3.關閉流
        raf1.close();
        raf2.close();
    }

    /**
     * 使用RandomAccessFile實現數據的插入效果
     */
    @Test public void randomAccessFileTest2() throws IOException {

        RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw");
        //將指針調到角標爲3的位置
        raf1.seek(3);
        //保存指針3後面的所數據到StringBuilder中
        StringBuilder builder = new StringBuilder((int)new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while ((len = raf1.read(buffer)) != -1) {
            builder.append(new String(buffer, 0, len));
        }
        //調回指針
        raf1.seek(3);
        raf1.write("AAA".getBytes());

        //將StringBuilder中的數據寫入到文件中
        raf1.write(builder.toString().getBytes());
        raf1.close();
    }
}

八、Path、Paths、Files的使用

1. Path

Path用於替換原有的File類。
該接口的實現是不可變且安全的,可供多個並行線程使用。

2. Paths

此類僅由靜態方法組成,通過轉換路徑字符串返回Path或URI 。

Paths類提供了get()方法用來獲取Path對象。
在這裏插入圖片描述
Paths的常用方法
在這裏插入圖片描述

3. Files

主要用於操作文件或文件目錄的工具類
常用方法
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章