一,IO流概述及其分類
- 1.概念
- IO流用來處理設備之間的數據傳輸
- Java對數據的操作是通過流的方式
- Java用於操作流的類都在IO包中
- 流按流向分爲兩種:輸入流,輸出流。
- 流按操作類型分爲兩種:
- 字節流 : 字節流可以操作任何數據,因爲在計算機中任何數據都是以字節的形式存儲的
- 字符流 : 字符流只能操作純字符數據,比較方便。
- 2.IO流常用父類
- 字節流的抽象父類:
- InputStream
- OutputStream
- 字符流的抽象父類:
- Reader
- Writer
- 字節流的抽象父類:
- 3.IO程序書寫
- 使用前,導入IO包中的類
- 使用時,進行IO異常處理
- 使用後,釋放資源
- read()一次讀取一個字節
FileInputStream fis = new FileInputStream("aaa.txt"); //創建一個文件輸入流對象,並關聯aaa.txt int b; //定義變量,記錄每次讀到的字節 while((b = fis.read()) != -1) { //將每次讀到的字節賦值給b並判斷是否是-1 System.out.println(b); //打印每一個字節 } fis.close(); //關閉流釋放資源
因爲字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111
那麼這11111111是byte類型的-1,我們的程序是遇到-1就會停止不讀了,後面的數據就讀不到了,所以在讀取的時候用int類型接收,如果11111111會在其前面補上
24個0湊足4個字節,那麼byte類型的-1就變成int類型的255了這樣可以保證整個數據讀完,而結束標記的-1就是int類型
- write()一次寫出一個字節
FileOutputStream fos = new FileOutputStream("bbb.txt"); //如果沒有bbb.txt,會創建出一個
//fos.write(97); //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte
fos.write(98);
fos.write(99);
fos.close();
- FileOutputStream的構造方法寫出數據如何實現數據的追加寫入
FileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果沒有bbb.txt,會創建出一個 //fos.write(97); //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte fos.write(98); fos.write(99); fos.close();
- FileInputStream讀取
-
FileOutputStream寫出
-
FileInputStream fis = new FileInputStream("致青春.mp3"); //創建輸入流對象,關聯致青春.mp3 FileOutputStream fos = new FileOutputStream("copy.mp3");//創建輸出流對象,關聯copy.mp3 int b; while((b = fis.read()) != -1) { fos.write(b); } fis.close(); fos.close();
七,拷貝音頻文件畫原理圖
- A:案例演示
- 字節流一次讀寫一個字節複製音頻
- 弊端:效率太低
八,字節數組拷貝之available()方法
- A:案例演示
- int read(byte[] b):一次讀取一個字節數組
- write(byte[] b):一次寫出一個字節數組
- available()獲取讀的文件所有的字節個數
-
弊端:有可能會內存溢出
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
byte[] arr = new byte[fis.available()]; //根據文件大小做一個字節數組
fis.read(arr); //將文件上的所有字節讀取到數組中
fos.write(arr); //將數組中的所有字節一次寫到了文件上
fis.close();
fos.close();
九,定義小數組
- write(byte[] b)
- write(byte[] b, int off, int len)寫出有效的字節個數
-
字節流一次讀寫一個字節數組複製圖片和視頻
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
int len;
byte[] arr = new byte[1024 * 8]; //自定義字節數組
while((len = fis.read(arr)) != -1) {
//fos.write(arr); fos.write(arr, 0, len); //寫出字節數組寫出有效個字節個數 }
}
fis.close(); fos.close();
- A:緩衝思想
- 字節流一次讀寫一個數組的速度明顯比一次讀寫一個字節的速度快很多,
- 這是加入了數組這樣的緩衝區效果,java本身在設計的時候,
- 也考慮到了這樣的設計思想(裝飾設計模式後面講解),所以提供了字節緩衝區流
- B.BufferedInputStream
- BufferedInputStream內置了一個緩衝區(數組)
- 從BufferedInputStream中讀取一個字節時
- BufferedInputStream會一次性從文件中讀取8192個, 存在緩衝區中, 返回給程序一個
- 程序再次讀取時, 就不用找文件了, 直接從緩衝區中獲取
- 直到緩衝區中所有的都被使用過, 才重新從文件中讀取8192個
- C.BufferedOutputStream
- BufferedOutputStream也內置了一個緩衝區(數組)
- 程序向流中寫出字節時, 不會直接寫到文件, 先寫到緩衝區中
- 直到緩衝區寫滿, BufferedOutputStream纔會把緩衝區中的數據一次性寫到文件裏
-
D.拷貝的代碼 (下面)
-
E.小數組的讀寫和帶Buffered的讀取哪個更快?
- 定義小數組如果是8192個字節大小和Buffered比較的話
- 定義小數組會略勝一籌,因爲讀和寫操作的是同一個數組
- 而Buffered操作的是兩個數組
FileInputStream fis = new FileInputStream("致青春.mp3"); //創建文件輸入流對象,關聯致青春.mp3
BufferedInputStream bis = new BufferedInputStream(fis); //創建緩衝區對fis裝飾
FileOutputStream fos = new FileOutputStream("copy.mp3"); //創建輸出流對象,關聯copy.mp3
BufferedOutputStream bos = new BufferedOutputStream(fos); //創建緩衝區對fos裝飾
int b;
while((b = bis.read()) != -1) {
bos.write(b);
}
bis.close(); //只關裝飾後的對象即可
bos.close();
- flush()方法
- 用來刷新緩衝區的,刷新後可以再次寫出
- close()方法
- 用來關閉流釋放資源的的,如果是帶緩衝區的流對象的close()方法,不但會關閉流,還會再關閉流之前刷新緩衝區,關閉後不能再寫出
- 字節流讀取中文的問題
- 字節流在讀中文的時候有可能會讀到半個中文,造成亂碼
- 字節流寫出中文的問題
- 字節流直接操作的字節,所以寫出中文必須將字符串轉換成字節數組
- 寫出回車換行 write("\r\n".getBytes());
-
try finally嵌套
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("aaa.txt");
fos = new FileOutputStream("bbb.txt");
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
} finally {
try {
if(fis != null)
fis.close();
}finally {
if(fos != null)
fos.close();
}
}
十五,流的標準處理異常代碼1.7版本
-
try close
- 原理
- 在try()中創建的流對象必須實現了AutoCloseable這個接口,如果實現了,在try後面的{}(讀寫代碼)執行後就會自動調用,流對象的close方法將流關掉
try(
FileInputStream fis = new FileInputStream("aaa.txt");
FileOutputStream fos = new FileOutputStream("bbb.txt");
MyClose mc = new MyClose();
){
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
}
十六,圖片加密
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg"));
int b;
while((b = bis.read()) != -1) {
bos.write(b ^ 123);
}
bis.close();
bos.close();
十七,拷貝文件
-
在控制檯錄入文件的路徑,將文件拷貝到當前項目下
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個文件路徑");
String line = sc.nextLine(); //將鍵盤錄入的文件路徑存儲在line中
File file = new File(line); //封裝成File對象
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file.getName());
int len;
byte[] arr = new byte[8192]; //定義緩衝區
while((len = fis.read(arr)) != -1) {
fos.write(arr,0,len);
}
fis.close();
fos.close();
十八,錄入數據拷貝到文件
-
將鍵盤錄入的數據拷貝到當前項目下的text.txt文件中,鍵盤錄入數據當遇到quit時就退出
Scanner sc = new Scanner(System.in);
FileOutputStream fos = new FileOutputStream("text.txt");
System.out.println("請輸入:");
while(true) {
String line = sc.nextLine();
if("quit".equals(line))
break;
fos.write(line.getBytes());
fos.write("\r\n".getBytes());
}
fos.close();