一、IO流概念:
1、基本概念
2、IO流分類
3、java.io流的四大家族
4、流的close和flush方法
5、java.id下常用的16個流
二、FileInputStream字節輸入流
1、FileInputStream完成字節流輸入的流程
2、使用while優化FileInputStream讀取流程
3、FileInputStream最終版,使用byte數組讀取
4、FileInputStream的available
5、FileInputStream的skip方法
三、FileOutputStream字節輸出流
1、FileOutputStream概念
2、FileOutputStream輸出流程
3、改進FileInputStream+String輸出
4、文件復制(FileInputStream+FileOutputStream)
四、FileReader與FileWrite
1、FileReader概念
2、舉例FileReader
3、FileWrite概念:
4、舉例FileWrite:
5、復制普通文件(FileReader與FileWrite):
五、帶有緩沖區的字符流
1、BufferedReader概念:
2、舉例說明BufferedReader:
3、節點流與包裝流
4、BufferedWrite:帶有緩沖區的字符輸出流
六、數據流
1、DataOutputStream概念
2、舉例說明:DataOutputStream
3、DataInputStream流概念:
4、舉例說明:DataInputStream
七、標准輸出流
1、PrintStream標准字節輸出流:
2、更改標准輸出流的輸出方向
3、日志工具生成原理:
八、File類
https://www.cnblogs.com/mrwhite2020/p/14322392.html
九、對象流
https://www.cnblogs.com/mrwhite2020/p/14322446.html
十、IO和Properties
https://www.cnblogs.com/mrwhite2020/p/14322463.html
------------------------------------------分割線,以下為正文-------------------------------------------------
I:Input
O:Output
通過IO可以完成硬盤文件的讀和寫。
(1)按照流的方向分類:
輸入流(Input)或者稱為讀(Reader)
輸出流(Output)或者稱為寫(Write)
(2)按照讀取數據方式不同分類:
字節流:按照字節方式讀取數據,一次讀取1個字節byte,等同一個8個二進制位,這種流是萬能的,什么類型的文件都可以讀取,包括:文本文件、圖片、視頻、聲音等
字符流:按照字符方式讀取數據,一次讀取一個字符,這種流是為了方便讀取普通文件而存在,這種流不能讀取圖片、聲音、視頻、word等,只能讀取純文本文件。
假設文件test.txt 內容為:"h世界"
字節流讀取:第一次讀'h'(占用一個字節),第二次讀'世'字符的一半(占用一個字節)
字符流讀取:第一次讀'h'(占用一個字節),第二次讀'世'字符(占用一個字符)
(1)java.io.InputStream字節輸入流
(2)java.io.OutputStream字節輸出流
(3)java.io.Reader字符輸入流
(4)java.io.Writer字符輸出流
在java中以Stream結尾都是字節流,以Reader/Writer結尾都是字符流
(1)close()
所有的流都實現java.io.closeble接口,都是可以關閉的,都右close方法。
流是一個管理,是內存與硬盤之間的通道,用完之后一定要關閉,不然會耗費很多資源,養成好習慣,用完流一定要關閉。
(2)flush()
所有的輸出流都實現了java.io.Flushable接口,都可以刷新,都包含flush方法。
養成好習慣,輸出流輸出玩都需要flush刷新一下,表示將通道/管道當中的剩余未輸出的數據強行輸出完,即清空管道,沒有使用flush方法會導致數據丟失
(1)文件專屬:
java.io.FileInputStream;
java.io.FileOutputStream;
java.io.FileReader;
java.io.FileWriter;
(2)轉換流:字節流轉為字符流
java.io.InputStream;
java.io.OutputStream;
(3)緩沖區專屬:
java.io.BufferedInputStream;
java.io.BufferedOutputStream;
java.io.BufferedReader;
java.io.BufferedWriter;
(4)數據專屬:
java.io.DataInputStream;
java.io.DataOutputStream;
(5)標准輸出流:
java.io.PrintStream;
java.io.PrintWriter;
(6)對象專屬:
java.io.ObjectInputStream;
java.io.ObjectOutputStream;
(1)准備文件如下:
(2)創建字節流輸入對象,Idea自動將路徑變斜杠
(3)alt+回車添加try+catch或者上報異常,這里選擇try+catch
(4)第二種文件路徑編寫方式"\"與"//"等價
(5)增加finally語句且初始化流放在try+catch語句外,並添加流的關閉,流關閉前需要增加流的判空ifn可默認生成 if(fis==null)
(6)增加流的讀取,並添加try+catch使用alt+回車,這里建議選擇第一種異常
第一種:增加catch使用細粒度的異常
第二種:方法聲明異常
第三種:替換外層FIleNotFount為IO異常
第四種:內層在增加try+catch
(7)查看打印結果為a對應的字符ascII碼值97
(8)可重復讀取6次,最后一次讀取不到返回-1
2、使用while優化FileInputStream讀取流程
3、FileInputStream最終版,使用byte數組讀取
(1)查看剩余的字節數
(2)available的作用:可以不適用while循環,直接一次讀取全部的字節,但是不適合大的文件,因為byte數組不能太大
字節輸出流,從內存到硬盤
(1)使用byte數組+write方法+flush方法寫入
(2)檢查文件結果,相對路徑為項目根目錄下:
(3)再次執行,會將原文件中內容覆蓋,依然輸出:abcdab
(4)修改構造方法,true代表文本的追加
(5)查看相對路徑下的文本執行結果:文本追加了內容
(1)使用String轉byte數組輸出
(2)查看輸出結果,追加一段String字符串
4、文件復制(FileInputStream+FileOutputStream)
(1)流程:拷貝過程是一邊讀、一邊寫;文件類型任意,是萬能的
(2)舉例文件復制:
1 package JAVAADVANCE; 2
3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7
8 public class TestAdvance33IOTest08 { 9 public static void main(String[] args) { 10 FileInputStream fis=null; 11 FileOutputStream fos=null; 12 try { 13 //創建一個輸入對象流
14 fis=new FileInputStream("D:\\javaTest\\inFile\\甜蜜家園第01集.mp4"); 15 //創建一個輸出對象流
16 fos=new FileOutputStream("D:\\javaTest\\outFile\\甜蜜家園第01集.mp4"); 17 //准備一個byte數組,1024byte=1KB,*1024=1M,一次最多讀1M
18 byte[] bytes=new byte[1024*1024]; 19 int readCount=0; 20 while ((readCount=fis.read(bytes))!=-1) 21 { 22 //讀取多少,寫多少
23 fos.write(bytes,0,readCount); 24 } 25 fos.flush(); 26 } catch (FileNotFoundException e) { 27 e.printStackTrace(); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 } finally { 31 //fos與fis的關閉分開try catch比較好,避免互相影響,有流沒有關閉
32 if (fos != null) { 33 try { 34 fos.close(); 35 } catch (IOException e) { 36 e.printStackTrace(); 37 } 38 } 39 if(fis!=null){ 40 try { 41 fis.close(); 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 } 46 } 47
48
49
50
51 } 52 }
查看文件輸出結果
\
文件字符輸入流,只能讀取普通文本,讀取文本內容時比較方便、快捷
1 package JAVAADVANCE; 2 import java.io.*; 3 public class TestAdvance33IOTest09FileReader { 4 public static void main(String[] args) { 5 FileReader reader= null; 6 try { 7 //創建字符輸入流
8 reader=new FileReader("C:\\Users\\Mr.White\\IdeaProjects\\javaAdvance\\myTestFile01"); 9 //開始讀,使用char數組,一次讀取4個字符
10 char[] chars=new char[4]; 11 int readCount=0; 12 while ((readCount=reader.read(chars))!=-1){ 13 System.out.println(new String(chars,0,readCount)); 14 } 15 } catch (FileNotFoundException e) { 16 e.printStackTrace(); 17 } catch (IOException e) { 18 e.printStackTrace(); 19 } finally { 20 if (reader != null) { 21 try { 22 reader.close(); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 } 28 } 29 }
檢查源文件與讀取的內容
文件字符輸出流,只能輸出普通文本
1 package JAVAADVANCE; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 public class TestAdvance33IOTest10FileWrite { 5 public static void main(String[] args) { 6 FileWriter out = null; 7 try { 8 //創建字符輸出流對象,true使用追加寫入模式,否則重新執行會覆蓋
9 out=new FileWriter("fileWriteTest01",true); 10 //開始寫,使用char數組
11 char[] chars={'我','是','中','國','人'}; 12 //寫入全部char數組
13 out.write(chars); 14 //再寫入部分char數組,第3個字符開始,3個字符
15 out.write(chars,2,3); 16 //直接寫入String
17 out.write("我是個JAVA工程師"); 18 out.flush(); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 }finally { 22 if (out != null) { 23 try { 24 out.close(); 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } 28 } 29 } 30 } 31 }
查看輸出結果,相對路徑為工程根目錄下
5、復制普通文件(FileReader與FileWrite):
(1)使用FileReader與FileWrite進行拷貝,只能拷貝普通文本文件
(2)舉例復制普通文件:
1 package JAVAADVANCE; 2 import java.io.FileNotFoundException; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 public class TestAdvance33IOTest11NormalFileCopy { 7 public static void main(String[] args) { 8 FileReader in =null; 9 FileWriter out = null; 10 try { 11 //創建字符輸入流
12 in=new FileReader("D:\\javaTest\\inFile\\fileWriteTest01"); 13 //創建字符輸出流
14 out=new FileWriter("D:\\javaTest\\outFile\\fileWriteTest01"); 15 //一邊讀一邊寫
16 char[] chars=new char[1024*512]; //一次讀取1M文件
17 int readCount=0; 18 while ((readCount=in.read(chars))!=-1){ 19 out.write(new String(chars,0,readCount)); 20 } 21 //寫完后刷新
22 out.flush(); 23 } catch (FileNotFoundException e) { 24 e.printStackTrace(); 25 } catch (IOException e) { 26 e.printStackTrace(); 27 } finally { 28 if (in != null) { 29 try { 30 in.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 if (out != null) { 36 try { 37 out.close(); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 } 42 } 43 } 44 }
查看復制后結果
帶有緩沖區的字符輸入流,使用此流不需要自定義char數組,或者說不需要自定義byte數組,自帶緩沖區。
(1)准備文件
(2)按照行讀取文件
package JAVAADVANCE; import java.io.*; public class TestAdvance33IOTest12BufferedReader { //異常先拋出
public static void main(String[] args) throws IOException { FileReader reader=new FileReader("D:\\javaTest\\inFile\\fileWriteTest02"); //FileReader為節點流,BufferedReader為包裝流/處理流
BufferedReader br=new BufferedReader(reader); //讀第一行
String firstLine = br.readLine(); System.out.println(firstLine); //讀第二行
String secondLine = br.readLine(); System.out.println(secondLine); //讀第三行
String thirdLine = br.readLine(); System.out.println(thirdLine); //只需要關閉最外層的流,對於包裝流來說
br.close(); } }
(3)循環讀取全部文件
1 package JAVAADVANCE; 2 import java.io.BufferedReader; 3 import java.io.FileReader; 4 import java.io.IOException; 5 public class TestAdvance33IOTest12BufferedReader02 { 6 //異常先拋出
7 public static void main(String[] args) throws IOException { 8 FileReader reader=new FileReader("D:\\javaTest\\inFile\\fileWriteTest02"); 9 //FileReader為節點流,BufferedReader為包裝流/處理流
10 BufferedReader br=new BufferedReader(reader); 11 //使用String字符串讀取
12 String s=null; 13 while ((s=br.readLine())!=null){ 14 System.out.println(s); 15 } 16 //只需要關閉最外層的流,對於包裝流來說
17 br.close(); 18 } 19 }
檢查執行結果
(4)print方法測試readLine方法不帶換行符
1 package JAVAADVANCE; 2 import java.io.BufferedReader; 3 import java.io.FileReader; 4 import java.io.IOException; 5 public class TestAdvance33IOTest12BufferedReader02 { 6 //異常先拋出
7 public static void main(String[] args) throws IOException { 8 FileReader reader=new FileReader("D:\\javaTest\\inFile\\fileWriteTest02"); 9 //FileReader為節點流,BufferedReader為包裝流/處理流
10 BufferedReader br=new BufferedReader(reader); 11 //使用String字符串讀取
12 String s=null; 13 while ((s=br.readLine())!=null){ 14 //print方法測試readLine方法不帶換行符
15 System.out.print(s); 16 } 17 //只需要關閉最外層的流,對於包裝流來說
18 br.close(); 19 } 20 }
查看執行結果
(1)節點流與包裝流都是相對而言
(2)舉例說明:節點流與包裝流
以下例子:
in與reader:in為節點流,reader為包裝流
reader與br:reader與節點流,br為包裝流
package JAVAADVANCE; import java.io.*; public class TestAdvance33IOTest12BufferedReader03 { //異常先拋出
public static void main(String[] args) throws IOException { FileInputStream in=new FileInputStream("D:\\javaTest\\inFile\\fileWriteTest02"); //通過InputStreamReader轉換流將字節流轉換為字符流
InputStreamReader reader=new InputStreamReader(in); BufferedReader br =new BufferedReader(reader); //使用String字符串讀取
String line=null; while ((line=br.readLine())!=null){ //print方法測試readLine方法不帶換行符
System.out.println(line); } //只需要關閉最外層的流,對於包裝流來說
br.close(); } }
查看運行結果:
(1)舉例說明BufferedWrite
package JAVAADVANCE; import java.io.*; public class TestAdvance33IOTest13BufferedWrite { //異常先拋出
public static void main(String[] args) throws IOException { BufferedWriter out=new BufferedWriter(new FileWriter("D:\\javaTest\\outFile\\fileWriteTest02")); out.write("hello world"); out.write("\nhello kitty"); out.flush(); out.close(); } }
查看執行結果
(2)使用包裝流追加輸出
package JAVAADVANCE; import java.io.*; public class TestAdvance33IOTest13BufferedWrite02 { //異常先拋出
public static void main(String[] args) throws IOException { BufferedWriter out=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\javaTest\\outFile\\fileWriteTest02",true))); out.write("\n這是繼續使用包裝流追加的文字"); out.flush(); out.close(); } }
查看執行結果:
數據專屬的流
這個流可以將數據連同數據的類型一並寫入文件
注意:這個文件不同普通文本文檔(這個文件使用記事本打不開)
package JAVAADVANCE; import java.io.*; public class TestAdvance33IOTest14DataOutputStream01 { //異常先拋出
public static void main(String[] args) throws IOException { //創建數據專屬字節輸出流
DataOutputStream dos=new DataOutputStream(new FileOutputStream("D:\\javaTest\\outFile\\fileWriteTest03")); byte b=100; short s=200; int i=300; float t=400F; double d=3.14; boolean sex=false; char c='a'; dos.writeByte(b); dos.writeShort(s); dos.writeInt(i); dos.writeFloat(t); dos.writeDouble(d); dos.writeBoolean(sex); dos.writeChar(c); dos.flush(); dos.close(); } }
查看文件結果:無法使用記事本或notepad++打開,需要使用DataInputStream流打開,並且讀的順序需要與寫的順序一致。
數據字節輸入流,DataOutputStream流寫的文件只能使用DataInputStream打開,並且讀的順序需要和寫的順序一致。
1 package JAVAADVANCE; 2 import java.io.*; 3 public class TestAdvance33IOTest15DataInputStream01 { 4 //異常先拋出
5 public static void main(String[] args) throws IOException { 6 //創建數據專屬字節輸入流
7 DataInputStream dis =new DataInputStream(new FileInputStream("D:\\javaTest\\outFile\\fileWriteTest03")); 8 //開始讀,讀的順序要與寫的時候保持一致。
9 byte b= dis.readByte(); 10 short s=dis.readShort(); 11 int i=dis.readInt(); 12 float t =dis.readFloat(); 13 double d=dis.readDouble(); 14 boolean sex=dis.readBoolean(); 15 char c=dis.readChar(); 16 dis.close(); 17 System.out.println(b); 18 System.out.println(s); 19 System.out.println(i); 20 System.out.println(t); 21 System.out.println(d); 22 System.out.println(sex); 23 System.out.println(c); 24
25 } 26 }
查看顯示結果
標准字節輸出流,默認輸出到控制台。
1 package JAVAADVANCE; 2 import java.io.IOException; 3 import java.io.PrintStream; 4 public class TestAdvance33IOTest16PrintStream01 { 5 //異常先拋出
6 public static void main(String[] args) throws IOException { 7 //標准輸出流直接輸出到控制台
8 System.out.println("hello world"); 9 //換一種寫法
10 PrintStream ps=System.out; 11 ps.println("hello zhangsan"); 12 ps.println("hello lisi"); 13 //標准輸出流不需要手動關閉
14 } 15 }
1 package JAVAADVANCE; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.PrintStream; 5 public class TestAdvance33IOTest16PrintStream01 { 6 //異常先拋出
7 public static void main(String[] args) throws IOException { 8 //更改標准輸出流的輸出方向,指向log文件
9 System.setOut(new PrintStream(new FileOutputStream("log"))); 10 //再次輸出
11 System.out.println("hello world"); 12 System.out.println("hello kitty"); 13 } 14 }
查看項目根目錄的輸出文件
package JAVAADVANCE; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.text.SimpleDateFormat; import java.util.Date; public class TestAdvance33IOTest16LogTest { //異常先拋出
public static void log(String msg) { try { PrintStream out=new PrintStream(new FileOutputStream("log.txt",true)); //改變文件的輸出方向
System.setOut(out); //當前日期格式
Date nowTime = new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); String strTime=sdf.format(nowTime); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
編寫測試程序開始測試日志打印
1 package JAVAADVANCE; 2 public class TestAdvance33IOTest16LogTest { 3 public static void main(String[] args) { 4 //測試工具是否好用
5 TestAdvance33IOTest16PrintStream02.log("調用了Sytem的gc()方法,建議啟動垃圾回收"); 6 TestAdvance33IOTest16PrintStream02.log("調用了userService的dosome()方法"); 7 TestAdvance33IOTest16PrintStream02.log("用戶正在嘗試登錄,驗證失敗"); 8 } 9 }
查看輸出結果
File類參照如下章節:
https://www.cnblogs.com/mrwhite2020/p/14322392.html
對象流、序列化與反序列化參考如下章節:
https://www.cnblogs.com/mrwhite2020/p/14322446.html
IO和Properties聯合使用參考如下章節:
https://www.cnblogs.com/mrwhite2020/p/14322463.html