20.01_IO流概述及其分類
IO流用來處理設備之間的數據傳輸
Java對數據的操作是通過流的方式
Java用于操作流的類都在IO包中
流按流向分為兩種:輸入流,輸出流。
-
流按操作類型分為兩種:
- 字節流 : 字節流可以操作任何數據,因為在計算機中任何數據都是以字節的形式存儲的
- 字符流 : 字符流只能操作純字符數據,比較方便。
-
字節流的抽象父類:
-
InputStream
字節輸入流所有類的超類 -
OutputStream
字節輸出流所有類的超類
-
-
字符流的抽象父類:
-
Reader
、Writer
-
-
3.IO程序書寫
- 使用前,導入IO包中的類
- 使用時,進行IO異常處理
- 使用后,釋放資源
20.02_IO流(FileInputStream)
FileInputStream input = new FileInputStream("xxoo.txt"); //可能拋出FileNotFoundException
int x ;
while( (x = input.read()) != -1){ //從文件中讀取一個字節(一個字符的二進制數值)
System.out.println(x);
}
input.close(); //關閉釋放資源
20.03_read()方法返回值為什么是int,而不是byte?
因為字節輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到111111111那么這11111111是byte類型的-1,我們的程序是遇到-1就會停止不讀了,后面的數據就讀不到了,所以在讀取的時候用int類型接收,如果11111111會在其前面補上24個0湊足4個字節,那么byte類型的-1就變成int類型的255了這樣可以保證整個數據讀完,而結束標記的-1就是int類型
read()方法返回值為什么是int.png
20.04_IO流(FileOutputStream)
// FileOutputStream 創建的時候(下面這個構造方法),如果文件不存在,會自動創建,如果文件存在,就會清空文件。
FileOutputStream ouput = new FileOutputStream("xxoo.txt");
ouput.write(97); //雖然寫出的是一個int數,但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte
ouput.write(98); //一次write()操作會覆蓋原來文件的內容
ouput.close();
20.05_IO流(FileOutputStream追加)
// 使用此構造方法,代表每次寫文件 都是追加 文件內容末尾
FileOutputStream fop = new FileOutputStream("xxoo.txt", true);
fop.write(100);
fop.close();
20.06_IO流(拷貝圖片)
FileInputStream fis = new FileInputStream("xxoo.png"); //讀文件
FileOutputStream fos = new FileOutputStream("copy.png"); //寫文件
int b ;
while( (b = fis.read()) != -1 ) {
fos.write(b);;
}
fis.close();
fos.close();
20.07_IO流(拷貝大文件問題)
- 當讀寫一個大文件時,比如一個普通MP3文件,4Mb左右,就有4百多萬個字節,而字節流一次只讀寫一個字節,那么拷貝一個MP3就需要讀寫將近9百多萬次,效率將會十分低下。
20.08_IO流(字節數組拷貝之available()方法)
-
int read(byte[] b)
:一次讀取一個字節數組 -
write(byte[] b)
:一次寫出一個字節數組 -
available()
獲取讀的文件所有的字節個數 - 弊端:有可能會內存溢出
FileInputStream input = new FileInputStream("xxoo.png");
FileOutputStream output = new FileOutputStream("copy.png"); //寫文件
byte[] data = new byte[input.available()]; //根據文件大小做一個字節數組
input.read(arr); //將文件上的所有字節讀取到數組中
output.write(data); //將數組中的所有字節一次寫到了文件上
input.close();
output.close();
20.10_IO流(定義小數組的標準格式)
FileInputStream fis = new FileInputStream("xxoo.png");
FileOutputStream fos = new FileOutputStream("copy.png");
byte[] data = new byte[1024 * 10]; //代表 10Kb
int len ;
while( (len = fis.read(data)) != -1){
fos.write(data, 0, len);
}
fos.close();
fis.close();
// write(byte[] b, int off, int len) 從byte數組 的off讀,讀取len個長度的有效內容
20.11_BufferedInputStream和BufferOutputStream拷貝
-
A: 緩沖思想
- 字節流一次讀寫一個數組的速度明顯比一次讀寫一個字節的速度快很多,
- 這是加入了數組這樣的緩沖區效果,java本身在設計的時候,
- 也考慮到了這樣的設計思想(裝飾設計模式后面講解),所以提供了字節緩沖區流
-
B. BufferedInputStream
-
BufferedInputStream
內置了一個緩沖區(數組) - 從
BufferedInputStream
中讀取一個字節時 -
BufferedInputStream
會一次性從文件中讀取8192個, 存在緩沖區中, 返回給程序一個 - 程序再次讀取時, 就不用找文件了, 直接從緩沖區中獲取
- 直到緩沖區中所有的都被使用過, 才重新從文件中讀取8192個
-
-
C. BufferedOutputStream
-
BufferedOutputStream
也內置了一個緩沖區(數組) - 程序向流中寫出字節時, 不會直接寫到文件, 先寫到緩沖區中
- 直到緩沖區寫滿,
BufferedOutputStream
才會把緩沖區中的數據一次性寫到文件里
-
-
D. 小數組的讀寫和帶Buffered的讀取哪個更快?
- 定義小數組如果是8192個字節大小和
Buffered
比較的話 - 定義小數組會略勝一籌,因為讀和寫操作的是同一個數組
- 而
Buffered
操作的是兩個數組
- 定義小數組如果是8192個字節大小和
FileInputStream fis = new FileInputStream("xxoo.png"); //創建輸入流對象
FileOutputStream fos = new FileOutputStream("copy.png"); //創建輸出流對象
// 這上下四句,可以使用匿名對象寫成2句
BufferedInputStream bis = new BufferedInputStream(fis); //創建緩沖區對象,對輸入流進行包裝
BufferedOutputStream bos = new BufferedOutputStream(fos); //創建緩沖區對象,對輸出流進行包裝
int data ;
while( (data = bis.read()) != -1 ) {
bos.write(data);
}
bis.close(); // 這里只需要對 緩沖對象 關閉即可,不用再去關閉 輸入出流
bos.close();
20.12_IO流(flush和close方法的區別)
-
flush()
方法- 用來刷新緩沖區的,刷新后可以再次寫出
-
close()
方法- 用來關閉流釋放資源的的,如果是帶緩沖區的流對象的close()方法,不但會關閉流,還會再關閉流之前刷新緩沖區,關閉后不能再寫出
20.13_IO流(字節流讀寫中文)
- 字節流讀取中文的問題
- 字節流在讀中文的時候有可能會讀到半個中文,造成亂碼
- 字節流寫出中文的問題
- 字節流直接操作的字節,所以寫出中文必須將字符串轉換成字節數組
- 寫出回車換行
write("\r\n".getBytes());
20.14_IO流(流的標準處理異常代碼1.6版本及其以前)
-
try finally
嵌套
以下代碼了解即可,可能老項目有類似代碼,現在最新eclipse(4.6.2)寫如下代碼依舊提示異常沒有處理錯誤的。
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();
}
}
20.15_IO流(流的標準處理異常代碼1.7版本)
// 因為 InputStream 實現了 AutoCloseable接口,所以會自動關閉
// 而 tyr(){} 會自動關閉 ()里面的對象,反之,()里面的對象必須實現了 AutoCloseable接口
try(
FileInputStream in = new FileInputStream("xxoo.txt");
FileOutputStream out = new FileOutputStream("xxoo.txt");
){
int data ;
while( (data = in.read()) != -1) {
out.write(data);
}
}
在try()中創建的流對象必須實現了AutoCloseable這個接口,
如果實現了,在try后面的{}(讀寫代碼)執行后就會自動調用,流對象的close方法將流關掉
20.16_IO流(圖片加密)
// 圖片加密,關鍵: 整數被異或兩次就是整數本身
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("xo.png"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("t.png"));
int len ;
while( (len = bis.read()) != -1) {
bos.write(len ^ 10); //為什么這里 使用 ^ ? 因為一個整數被 ^ 兩次,就是原來的整數
}
bis.close();
bos.close();
20.17_IO流(拷貝文件)
- 在控制臺錄入文件的路徑,將文件拷貝到當前項目下
Scanner sc = new Scanner(System.in);
System.out.println("請輸入文件的絕對路徑: ");
String path = sc.nextLine();
sc.close();
File file = new File(path);
if (!file.exists() || !file.isFile()) {
System.out.println("路徑不存在,或者路徑指向的不是一個文件!");
return;
}
System.out.println("拷貝中...");
FileInputStream in = new FileInputStream(file); //也可以使用 BufferedInputStream
FileOutputStream out = new FileOutputStream(file.getName());
byte[] data = new byte[1024 * 10]; // 自定義緩沖大學,10Kb
int len ;
while( (len = in.read(data)) != -1) {
out.write(data, 0, len);
}
in.close();
out.close();
System.out.println("拷貝成功...");
20.18_IO流(錄入數據拷貝到文件)
- 將鍵盤錄入的數據拷貝到當前項目下的text.txt文件中,鍵盤錄入數據當遇到quit時就退出
Scanner sc = new Scanner(System.in);
FileOutputStream out = new FileOutputStream("text.txt");
System.out.println("請輸入文件內容: ");
while(true) {
String text = sc.nextLine();
if("quit".equals(text)) break ;
out.write(text.getBytes());
out.write("\r\n".getBytes());
}
System.out.println("程序結束...");
sc.close();
out.close();
END。
我是小侯爺。
在魔都艱苦奮斗,白天是上班族,晚上是知識服務工作者。
如果讀完覺得有收獲的話,記得關注和點贊哦。
非要打賞的話,我也是不會拒絕的。