day20-Java IO流一(基本/拷貝文件)

20.01_IO流概述及其分類

  • IO流用來處理設備之間的數據傳輸

  • Java對數據的操作是通過流的方式

  • Java用于操作流的類都在IO包中

  • 流按流向分為兩種:輸入流輸出流

  • 流按操作類型分為兩種:

    • 字節流 : 字節流可以操作任何數據,因為在計算機中任何數據都是以字節的形式存儲的
    • 字符流 : 字符流只能操作純字符數據,比較方便。
  • 字節流的抽象父類:

    • InputStream 字節輸入流所有類的超類
    • OutputStream 字節輸出流所有類的超類
  • 字符流的抽象父類:

    • ReaderWriter
  • 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操作的是兩個數組
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。
我是小侯爺。
在魔都艱苦奮斗,白天是上班族,晚上是知識服務工作者。
如果讀完覺得有收獲的話,記得關注和點贊哦。
非要打賞的話,我也是不會拒絕的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容