檔案串流

串流固定寫法

為什麼一定要關閉串流?

不關閉串流,資料會存在記憶體,不會寫到檔案裡,有關閉的動作,才會有flush的動作,把資料寫到檔案裡。

關閉串流

因為串流產生的Error是屬於IOException,強制一定要補捉錯誤,若是Exception或RuntimeException就不用補捉錯誤。

  1. 宣告串流要在try…catch…final的外面,若宣告在try{}裡面,變數可見範圍只在try{}裡面,但串流不管有沒有錯誤,最後都一定要在final{}之中,close()關閉串流,宣告在try…catch…final的外面,變數的可見範圍才可以在final{}使用。
  2. 一定要關閉串流。
  3. 在try{}之中,建立串流。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  // 1.宣告串流
  FileInputStream fileInputStream = null;
  try {
    // 3.建立串流
    fileInputStream = new FileInputStream("/Users/cici/file_test");
  } catch (IOException e) {
    e.printStackTrace();
  } finally {
    // 2.關閉串流
    try {
      // 關閉時可能會有錯誤,所以要再catch一次
      if (fileInputStream != null)
        fileInputStream.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  }

自動關閉串流

JDK7有自動關閉串流的功能(Try-with-resources),不用處理關閉串流,也不能自行撰寫關閉串流,不然會呼叫close()二次(因為你又再寫一次close())。

在try()括號之間,建立串流。

1
2
3
4
5
6
7
8
  // 建立串流
  try (FileInputStream fileInputStream = new FileInputStream("/Users/cici/file_test")) {
    
  } catch (IOException e) {
    // 仍是要補捉IOException,有可能檔案沒有
    System.err.println("發生錯誤: " + e.getMessage());
    e.printStackTrace();
  }

FileInputStream讀取檔案

建構子

有下列二個建構子,參數為檔案或字串。

1
2
FileInputStream(File)
FileInputStream(String filename)

read()

  • int read() 一次讀一個位元組byte,傳回值為資料,型態為int,若值為其它類型,要轉型。

以下範例為每次只讀取一個byte,正常狀況下不會使用這個,因為一次讀一個byte速度很慢。

1
2
3
4
5
6
7
8
9
10
11
12
13
  // 宣告串流
  FileInputStream fileInputStream = null;
  try {
    // 建立串流
    fileInputStream = new FileInputStream("/Users/cici/testc/file_test");
    int data = 0;
    // -1 代表沒有資料讀取完畢
    while ((data = fileInputStream.read())!= -1) {
      // 強制轉型
      System.out.println((char) data);
    }
  } catch (IOException e) {
  // ...避免程式碼過多,截掉
h
e
l
l
o

read(byte[])

  • int read(byte[]) 一次讀取多個位元組,假設1024,一次讀取1024個位元組,並把讀到的資料放在byte[],傳回值為讀到的byte數量。

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  FileInputStream fileInputStream = null;
  try {
    // 建立串流
    fileInputStream = new FileInputStream("/Users/cici/testc/file_test");
    // 存放讀到的byte數量
    int len = 0;
    byte[] buffer = new byte[1024];
    // -1 代表沒有資料讀取完畢
    while ((len = fileInputStream.read(buffer)) != -1) {
      // 透過String建構子(位元組, 0, 讀到的byte數量),建立字串
      System.out.println(new String(buffer, 0, len));
    }
  }
  // ..避免程式碼過多,截掉
hello

值得注意的是,若buffer大小為3,若只使用new String(),沒有指定截取的數量。結果會出錯,因為每一次讀完,陣列buffer不會被清空,會存著上一次讀取的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
  FileInputStream fileInputStream = null;
  try {
    // 建立串流
    fileInputStream = new FileInputStream("/Users/cici/testc/file_test");
    // 存放每次讀取的數量
    int len = 0;
    byte[] buffer = new byte[3];
    // -1 代表沒有資料讀取完畢
    while ((len = fileInputStream.read(buffer)) != -1) {
      // byte[]轉字串
      System.out.println(new String(buffer));
    }
  }// ...避免程式碼過多,截掉
hel
lol

預期應該會出現hel與lo,並非hel與lol。

FileOutputStream寫檔案

建構子

有下列二個建構子,參數為檔案或字串,預設為覆蓋原有檔案,第2個參數是不覆蓋原有檔案,而是從檔案末尾開始寫資料。

1
2
3
4
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)

write(int)寫一個byte

1
2
3
4
5
6
7
  FileOutputStream fileOutputStream = null;
  try {
    // 建立檔案輸出串流
    fileOutputStream = new FileOutputStream("/Users/cici/testc/file_test");
    // 寫入輸出串流
    fileOutputStream.write('A');
  }// ...避免程式碼過多,截掉
A

write(byte[])

1
2
3
4
5
6
7
8
9
  // 宣告檔案輸出串流
  FileOutputStream fileOutputStream = null;
  try {
    // 建立檔案輸出串流
    fileOutputStream = new FileOutputStream("/Users/cici/testc/file_test");
    String str = "Hello world!";
    // 字串轉byte陣列
    fileOutputStream.write(str.getBytes());
  }// ...避免程式碼過多,截掉
Hello world!

write(byte[],int,int)

第2個參數,開始位置
第3個參數,寫入byte數量

1
write(byte[] b, int off, int len)
1
2
3
4
5
6
7
8
  FileOutputStream fileOutputStream = null;
  try {
    // 建立檔案輸出串流
    fileOutputStream = new FileOutputStream("/Users/cici/testc/file_test");
    String str = "Hello world!";
    // 寫入輸出串流
    fileOutputStream.write(str.getBytes(), 2, 6);
  }// ...避免程式碼過多,截掉
llo wo

FileInputStream與FileOutputStream

拷貝圖片,以下是邊讀邊寫。

之前提過,每一次讀完,陣列buffer不會被清空,會存著上一次讀取的值,所以一定要使用write(byte[],int,int),指定寫入的數量,假設最後一次迴圈只有讀到10byte,但buffer[1024],1024個byte只有前面10個byte是這次讀到的值,而剩下的1014byte都是上一個迴圈舊的資料,如果把1014byte也寫到檔案,會造成檔案損毀,無法開啟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    // 宣告串流
    FileInputStream fileInputStream = null;
    FileOutputStream fileOutputStream = null;
    try {
      // 建立輸入(讀)串流
      fileInputStream = new FileInputStream("/Users/cici/testc/1.png");
      // 建立輸出(寫)串流
      fileOutputStream = new FileOutputStream("/Users/cici/testc/2.png");
      // 存放每次讀取的數量
      int len = 0;
      byte[] buffer = new byte[1024];
      // -1 代表沒有資料讀取完畢
      while ((len = fileInputStream.read(buffer)) != -1) {
        // 邊讀邊寫
        // 一定要指定寫入數量len
        fileOutputStream.write(buffer, 0, len);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      // 關閉串流
      try {
        // 關閉讀串流
        if (fileInputStream != null)
          fileInputStream.close();
        // 關閉寫串流
        if (fileOutputStream != null)
          fileOutputStream.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

FileReader讀取文字檔

只能讀取文字檔,不能讀取圖片或壓縮檔,可以處理中文字、UTF-8。

read()讀取字元

  • int read() 一次讀一個字元,傳回值為int。
    傳回值是真正的資料,每次讀取完的字元存放在data變數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  FileReader reader = null;
  try {
    // 檔案內容llo wo
    reader = new FileReader("/Users/cici/testc/file_test");
    // 存放值
    int data = 0;
    // -1 代表沒有資料讀取完畢
    while ((data = reader.read()) != -1) {
      System.out.println((char)data);
    }
  } catch (IOException e) {
    e.printStackTrace();
  } finally {
    // 關閉串流
    try {
      if (reader != null)
        reader.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
l
l
o
 
w
o

read(char[])

  • int read(char[]) 一次讀取多個字元,假設設定8,一次讀取8字元,並把讀到的資料放在char[]。
    傳回值是讀到的數量。
1
2
3
4
5
6
7
8
9
10
11
  FileReader reader = null;
  try {
    // 檔案內容llo wo
    reader = new FileReader("/Users/cici/testc/file_test");
    int len = 0;
    char[] buffer = new char[3];
    while ((len = reader.read(buffer)) != -1) {
      System.out.println(new String(buffer, 0, len));
    }
  }
  // ...避免程式碼過多,截掉
llo
 wo

FileWriter寫到文字檔

只能寫文字檔,不能寫圖片或壓縮檔,可以處理中文字、UTF-8。
一定要關閉串流,不然不會寫到檔案裡,只會暫存在記憶體。

write(int c)

寫入一個字元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  FileWriter writer = null;
  try {
    writer = new FileWriter("/Users/cici/testc/file_test");
    writer.write('A');
  } catch (IOException e) {
    e.printStackTrace();
  } finally {
    // 關閉串流
    try {
      if (writer != null)
        writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
A

write(char[])

1
2
3
4
5
6
  FileWriter writer = null;
  try {
    writer = new FileWriter("/Users/cici/testc/file_test");
    char[] chars  = {'A', 'B', 'C'};
    writer.write(chars);
  }
ABC

write(String)

輸入中文字串

1
2
3
4
5
  FileWriter writer = null;
  try {
    writer = new FileWriter("/Users/cici/testc/file_test");
    writer.write("測試");
  }
測試

write(String,int,int)

1
2
3
4
5
6
  FileWriter writer = null;
  try {
    writer = new FileWriter("/Users/cici/testc/file_test");
    // 從索引2,取2個
    writer.write("測試程式語言", 2, 2);
  }
程式

results matching ""

    No results matching ""