九、位元組流與字元流 9.1 IO的分類 輸入流 :把數據從其他設備上讀取到記憶體中的流。 輸出流 :把數據從記憶體 中寫出到其他設備上的流。 位元組流 :以位元組為單位,讀寫數據的流。 字元流 :以字元為單位,讀寫數據的流。 輸入流 輸出流 位元組流 位元組輸入流 InputStream 位元組輸出流 Outpu ...
九、位元組流與字元流
9.1 IO的分類
<段落>根據數據的流向分為:輸入流和輸出流。數據的類型分為:位元組流和字元流。
- 輸入流 :把數據從其他設備上讀取到記憶體中的流。
- 輸出流 :把數據從記憶體 中寫出到其他設備上的流。
- 位元組流 :以位元組為單位,讀寫數據的流。
- 字元流 :以字元為單位,讀寫數據的流。
頂級父類表:
輸入流 輸出流 位元組流 位元組輸入流 InputStream 位元組輸出流 OutputStream 字元流 字元輸入流 Reader 字元輸出流Writer 9.2位元組流輸出流
9.2.1 概述:
一切文件數據都是以二進位數字的形式保存,我們要時刻明確,無論使用什麼樣的流對象,底層傳輸始終為二進位數據。9.2.2 位元組輸出流的構造方法:
OutputStream有很多子類,我們從最簡單的一個子類開始。
java.io.FileOutputStream類是文件輸出流,用於將數據寫出到文件。
構造方法
public FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。notes: 在進行構造的時候,如果父目錄不存在,則會報錯,在創建時 父目錄存在,但是文件不存在,則會幫你創建。
public FileOutputStream(String name): 創建文件輸出流以指定的名稱寫入文件
notes:
當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有這個文件,會創建該文件。如果有這個文件,會清空這個文件的數據。
<wiz_code_mirror>
public static void main(String[] args) throws IOException {
// 創建 File 對象
File file = new File("a.txt");
// 創建文件輸出流對象
FileOutputStream fos = new FileOutputStream(file);
// 使用文件 名稱創建 輸出流對象
FileOutputStream fos1 = new FileOutputStream("a.txt");
fos.close();
fos1.close();
}
9.2.3位元組輸出流的基本共性方法:
java.io.OutputStream
抽象類是表示位元組輸出流的所有類的超類,將指定的位元組信息寫出到目的地。它定義了位元組輸出流的基本共性功能方法。
public void close()
:關閉此輸出流並釋放與此流相關聯的任何系統資源。public void flush()
:刷新此輸出流並強制任何緩衝的輸出位元組被寫出。public void write(byte[] b)
:將 b.length位元組從指定的位元組數組寫入此輸出流。public void write(byte[] b, int off, int len)
:從指定的位元組數組寫入 len位元組,從偏移量 off開始輸出到此輸出流。public abstract void write(int b)
:將指定的位元組輸出流。
tipps:
close方法,當完成流的操作時,必須調用此方法,釋放系統資源。
<wiz_code_mirror>
public static void main(String[] args) throws IOException{
// 在 寫的時候 是 將原來的刪除 然後再去 寫
FileOutputStream fos = new FileOutputStream("fos.txt");
// 寫 數據
fos.write(97);
fos.write(98);
//根據 位元組數組 寫數據
byte[] b = {'1','2','3','4'};
fos.write(b);
// 將指定 段 數據寫入
// write(byte[] b, int off, int len) ,每次寫出從off索引開始,len個位元組
fos.write(b,0,2);
// 關閉
fos.close();
}
-->輸出結果:
當沒有fos.txt文件時,寫入ab123412
有則將其覆蓋
tips:<wiz_code_mirror>
1.雖然 參數 為 int 類型 四個位元組 但是 只會保留一個位元組的信息寫出 2.流操作完畢後,必須釋放系統資源,調用close方法
數據追加續寫: (只需要在 原來的 構造方法 後再加 一個參數 ,true表示 續寫,false 表示清空數據)
每次都會 清空目標文件中的數據,如何保留目標文件中數據,還能繼續添加數據
構造方法:
寫出換行:
public FileOutputStream(File file, boolean append)
: 創建文件輸出流以寫入由指定的 File對象表示的文件。
public FileOutputStream(String name, boolean append)
\r 回車符 回到一行的開頭 \n 換行符另起一行
系統中
Windows 系統里 換行符合為 \r\n Unix系統里 沒行結尾只有 換行 即 \n; Mac系統里,每行結尾是 回車,即\r 。從 Mac OS X開始與Linux 統一。
public static void main(String[] args) throws IOException{
// 在 寫的時候 是 將原來的刪除 然後再去 寫
FileOutputStream fos = new FileOutputStream("fos.txt");
// 寫 數據
fos.write(97);
fos.write(98);
fos.write("\r\n".getBytes());
//根據 位元組數組 寫數據
byte[] b = {'1','2','3','4'};
fos.write(b);
// 將指定 段 數據寫入
fos.write(b,0,2);
// 關閉
fos.close();
}
結果是:
ab
123412
9.3位元組輸入流 InputStream
java.io.InputStream
抽象類是表示位元組輸入流的所有類的超類,可以讀取位元組信息到記憶體中。它定義了位元組輸入流的基本共性功能方法。
public void close()
:關閉此輸入流並釋放與此流相關聯的任何系統資源。
public abstract int read()
: 從輸入流讀取數據的下一個位元組。
public int read(byte[] b)
: 從輸入流中讀取一些位元組數,並將它們存儲到位元組數組 b中 。
tips:
9.3.1 構造方法
java.io.FileInputStream
類是文件輸入流,從文件中讀取位元組。構造方法
FileInputStream(File file)
: 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的 File對象 file命名。
FileInputStream(String name)
: 通過打開與實際文件的連接來創建一個 FileInputStream ,該文件由文件系統中的路徑名 name命名。
<wiz_code_mirror>當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有該文件,會拋出
FileNotFoundException
public static void main(String[] args) throws FileNotFoundException {
File file = new File("a.txt");
// 通過構造方法 創建 輸入流對象
FileInputStream fis = new FileInputStream(file);
FileInputStream fis1 = new FileInputStream("a.txt");
}
<wiz_code_mirror>9.3.2 方法
1.讀取位元組:read方法,每次可以讀取一個位元組的數據,提升為int類型,當讀取到文件末尾的時候 則會返回 -1 。
可以根據 -1 來判斷是否到達文件末尾:
public static void main(String[] args) throws IOException {
File file = new File("fos.txt");
// 通過構造方法 創建 輸入流對象
FileInputStream fis = new FileInputStream(file);
FileInputStream fis1 = new FileInputStream("fos.txt");
// 提升成 int 類型
int read = fis.read();
System.out.println("read = " + read); // 如果不轉換成 char 類型 則是97 轉成char類型則是 a
int read1 = fis.read();
System.out.println("read = " + read1);
int read2 = fis.read();
System.out.println("read = " + read2);
int read3 = fis.read();
System.out.println("read = " + read3);
// 讀取到文件末尾就返回 -1
fis.close();
fis1.close();
}
2.對迴圈進行改進 使用while 迴圈<wiz_code_mirror>
public static void main(String[] args) throws IOException {
// 創建文件對象
File file = new File("fos.txt");
// 創建 輸入流對象
FileInputStream fis = new FileInputStream(file);
// 通過while 迴圈 當 b != -1 時 退出
int b;
while ((b = fis.read()) != -1) {
System.out.println("b = " + (char) b);
}
// 關閉流對象
fis.close();
}
tips: 1.雖然讀取了一個位元組,但是會自動提升 為 int 類型 2. 流操作完畢後,必須釋放系統資源, 調用close方法 3.使用位元組數組讀取 : read(byte[] b), 每次讀取b個長度的位元組到數組中,返回讀取到的有效位元組個數 讀取到末尾時 返回 -1<wiz_code_mirror>
public static void main(String[] args) throws IOException{
// 使用文件名稱創建流對象.
FileInputStream fis = new FileInputStream("read.txt"); // 文件中為abcde
// 定義變數,作為有效個數
int len ;
// 定義位元組數組,作為裝位元組數據的容器
byte[] b = new byte[2];
// 迴圈讀取
while (( len= fis.read(b))!=-1) {
// 每次讀取後,把數組變成字元串列印
System.out.println(new String(b));
}
// 關閉資源
fis.close();
}
tips: 使用數組進行讀取,每次讀取多個位元組,減少系統見4的IO操作的次數,從而 提高了讀寫的效率,建議開發中使用<wiz_code_mirror>9.3.3視頻的複製
從已有的文件中讀取位元組,將該位元組寫出到另一個文件中
public static void main(String[] args) throws IOException {
File file = new File("D:\\111\\shipin.flv");
// 創建 輸入流 將文件讀入 到記憶體中
FileInputStream fis = new FileInputStream(file);
// 創建輸出流 將數據從記憶體寫入到 文件中
FileOutputStream fos = new FileOutputStream("D:\\2222\\flower.flv");
int len;
byte[] b = new byte[1024];
// 迴圈讀取
while ((len = fis.read(b)) != -1) {
// 寫數據
fos.write(b,0,len);
}
fos.close();
fis.close();
}
notes:<wiz_code_mirror>
流關閉原則: 先開後關,後開先關9.3.4位元組緩衝流包裝
構造方法: public BufferInputStream(InputStream in): 創建一個新的緩衝輸入流
public BufferOutputStream(OutputStream out):創建一個新緩衝輸出流
public static void main(String[] args) throws FileNotFoundException {
// 創建 位元組緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
// 創建 位元組緩衝輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
}
實現一個複製視頻的操作,聯繫 BufferInputStream 和 BufferOutputStream<wiz_code_mirror>
public static void main(String[] args) throws IOException {
// 複製一份視頻 用BuffOutputStream
// 創建一個 輸入流對象
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/福利贈送.flv"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("s.flv"));
int len;
byte[] b = new byte[1024*8];
while ((len = bis.read(b)) != -1){
bos.write(b);
bos.flush();
}
bos.close();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
9.4 字元流
當使用位元組流讀取文本文件時,可能會遇到一個小問題。就是遇到中文字元的時候,可能不會顯示完整的字元,那是因為一個中午字元 可能 占用多個位元組。所有java提供了一些字元流,以字元為單位讀寫數據,專門用於處理文本文件。9.4.1 字元輸入流【Reader】
java.io.Reader 抽象類是表搜狐用於讀取字元流的所有類的超類,可以讀取位元組信息到記憶體中。它定義了位元組輸入流的基本共性功能方法。
public void close()
:關閉此流並釋放與此流相關聯的任何系統資源。
public int read()
9.4.2 FileReader 類
java.io.FileReader 類是讀取字元文件的類,構造時使用系統預設的字元編碼和預設位元組緩衝區。
tips:
1.字元編碼:位元組與字元的對應規則。Windows 系統的中午編碼預設是GBK 編碼表
2.位元組緩衝區:一個位元組數組,用來臨時存儲位元組數據。
構造方法:
FileReader(File file)
: 創建一個新的 FileReader ,給定要讀取的File對象。FileReader(String fileName)
: 創建一個新的 FileReader ,給定要讀取的文件的名稱。
當你創建一個流對象時,必須傳入一個文件路徑,類似於FileInputStream<wiz_code_mirror>
public static void main(String[] args) throws FileNotFoundException {
File file = new File("a.txt");
// 創建字元輸入流對象
FileReader fr = new FileReader(file);
// 使用文件名創建流對象
FileReader fr1 = new FileReader("a.txt");
}
基本方法: 1.read方法,每次可以讀取一個字元的數據,提升為int類型,讀取到文件末尾,返回 -1 ,迴圈讀取
問:為什麼 返回值是 int 而不是 byte
<wiz_code_mirror>答:因為位元組輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是二進位形式存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111 那麼這111111111是byte類型的-1我們程式要是遇到 -1 就會停止不讀了,後面的數據就讀取不到了 所以選擇 int接受,如果111111111會在前面補上24個0湊足4個位元組,那麼byte類型的-1 就變成int類型的255了 這樣就可以保證整個數據讀完了,而結束標記的-1就是int類型。
public static void main(String[] args) throws IOException {
// a.txt 文件中 有 abc
File file = new