1. 程式人生 > >io流淺談

io流淺談

public 文件夾 parent 文章

IO流淺談

在這篇文章裏,我會分別和大家聊字節流和字符流
一字節流
File
 
  File:文件和目錄(文件夾)路徑名的抽象表示形式。 
  

  File的構造方法:
  		File(String pathname):把一個路徑名稱封裝成File對象
  		File(String parent, String child):把一個父路徑和一個子路徑封裝成一個File對象
  		File(File parent, String child):把一個父路徑File對象和一個子路徑封裝成一個File對象

		
     創建功能:
  		A:創建文件
  			public boolean createNewFile():如果文件不存在,就創建。否則,不創建。
			需求:D盤下造一個文件a.txt
  		B:創建目錄
  			public boolean mkdir():如果目錄不存在,就創建。否則,不創建。
			需求:D盤下造一個文件夾test
 			public boolean mkdirs():如果目錄不存在,就創建。否則,不創建。
 									即時父目錄不存在,也可以連父目錄一起創建。
      
      創建文件的時候,一定要保證路徑存在。
  
  刪除功能:
  		public boolean delete():既可以刪除文件,又可以刪除目錄。
 
  路徑問題:
  		A:絕對路徑	就是以盤符開始的路徑(d:\\test\\aaa\\b.txt)
  		B:相對路徑	就是不以盤符開始的路徑(a.txt)
  					一般都是相對應當前的項目而言的。
  
  註意事項:Java程序的刪除不走回收站,如果目錄內還有內容就不能刪除。
  		

	
   
  一些方法
  public boolean isDirectory():是否是目錄
  public boolean isFile():是否是文件
  public boolean exists():是否存在
  public boolean canRead():是否可讀
  public boolean canWrite():是否可寫
  public boolean isHidden():是否隱藏

 
  獲取功能
  public String getAbsolutePath():獲取絕對路徑
  public String getPath():獲取相對路徑
  public String getName():獲取名稱
    相對路徑是指相對於當前包而言的

二:字節流及字節高效流
2.1 I/O流的分類(畫圖講解)
  IO流分類:
  		流向:
  			輸入流
 			輸出流
  		數據類型:
  			字節流
  				字節輸入流
  				字節輸出流
 			字符流
  				字符輸入流
  				字符輸出流
  
  註意:一般我們在討論IO的分類時,默認是按照數據類型分的。
  
  字節流:
  		字節輸入流		InputStream(抽象類)
  		字節輸出流		OutputStream(抽象類)
  字符流:
  		字符輸入流		Reader
  		字符輸出流		Writer
  
  學習習慣:
  		字節流
 		字符流
  
 
  輸出流具體操作步驟如下:
  字節輸出流對象
  調用寫數據的方法
  釋放資源
 
做法:
A:	兩個構造的區別?
 		FileOutputStream(File file)
		FileOutputStream(String name)
		FileOutputStream fos  = new FileOutputStream("fos.txt");
		請問上面這個操作做了哪幾件事情?
		 * 1.創建了一個文件輸出流fos,指向文件a.txt
		 * 2.創建了a.txt這個文件
		
B:     fos.write("helloworld".getBytes());

C:		fos.close();關流

D:		fos.write("java".getBytes());


FileOutputStream寫數據的方法
write(byte[] b) 
write(int b) :一次寫一個字節
write(byte[] b, int off, int len) :一次寫一個字節數組的一部分
代碼實現(只是核心代碼)
        FileOutputStream fos = new FileOutputStream("b.txt");
		
		調用寫書數據的方法,寫書文件
		先一次寫一個字節
		write(int b) :
		fos.write(97);
		
		然後呢一次寫一個字節數組的一部分
		write(byte[] b, int off, int len) ;
		byte[] byf = {97,98,99,100};
		fos.write(byf, 1, 2);


字節輸入流:
具體操作步驟:
  字節輸入流操作步驟:
  A:創建字節輸入流對象
 FileInputStream  fis = new FileInputStream("a.txt");
 
  B:調用方法讀取數據
 一次讀取一個字節:read() -- 測試讀取不到內容的時候的返回值(並且用循環改進)
 
  C:釋放資源
 fis.close
    這裏舉一個例子:
	復制一個文件
          //1.封裝數據源和目的地
		FileInputStream fis = new FileInputStream("D://b.mp4");
		FileOutputStream fos = new FileOutputStream("d.mp4");
		
		//2.讀取數據源,寫入目的地
		int by;
		while ((by=fis.read())!=-1) {
			fos.write(by);
		}
		
		//3.釋放資源
		fos.close();
		fis.close();
 
  數據源:
  		IODemo.java	--	讀取數據	--	InputStream	--	FileInputStream	--	一次讀取一個字節
  目的地:
  		Copy.java	--	寫出數據	--	OutputStream -- FileOutputStream -- 一次寫一個字節



字節輸入流:
具體操作步驟:
  字節輸入流操作步驟:
  A:創建字節輸入流對象
 FileInputStream  fis = new FileInputStream("a.txt");
 
  B:調用方法讀取數據(一次讀取一個字節數組,提升效率)
 一次讀取一個字節數組: public int read(byte[] b):返回實際讀取長度,數據被讀取到數組中。
 -- 測試方法返回長度?根據String類的構造方法構造字符串
  C:釋放資源
 fis.close

 
 
 
  字節緩沖區流(也叫高效流):
  		BufferedInputStream(read() 一次讀取一個字節, public int read(byte[] b):返回實際讀取長度,數據被讀取到數組中。)
  		BufferedOutputStream(write(byte[] b))
  
  流
  		低級流: 基本的流,可以直接操作文件。
  		高級流:是操作基本流的流。
 

 
 
 

從這裏開始聊聊字符流 字符流
  String中的編碼和解碼問題。
  
  編碼:
  		把我們能夠看懂的字符轉換為看不懂的數據
 解碼:
  		把我們看不懂的數據轉換為看得懂的字符
  
  
 
 
 public byte[] getBytes(String charsetName)  按照給定的編碼方式,編碼字節數組(gbk,utf-8)
 String(byte[] bytes, String charsetName) 按照給定的編碼方式解碼字符數組
 
 		String s = "中國好";
		byte[] bytes = s.getBytes("utf-8");
		System.out.println(Arrays.toString(bytes));
		
		//String(byte[] bytes, String charsetName)
		System.out.println(new String(bytes,"gbk"));
 
 結論:用什麽編碼,就必須用什麽解碼。。
 
 轉換流 這邊不再多說(詳見十三天筆記)
 InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");
 int ch;
		while ((ch=isr.read())!=-1) {
			System.out.println((char)ch);
		}
		
		//關流
		isr.close();



字符流

Reader

Writer


IO流中的編碼和解碼問題

OutputStreamWriter:把字節輸出流轉換為字符輸出流

InputStreamReader:把字節輸入流轉換為字符輸入流

轉換流

寫入數據,把字節輸出流轉換為字符輸出流(不指定碼表)

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));

把字節輸出流轉換為字符輸出流(指定碼表)

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"), "GBK");

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"), "UTF-8");


讀取數據, 把字節輸入流轉換為字符輸入流(不指定碼表)

InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));

把字節輸入流轉換為字符輸入流(指定碼表)

InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "GBK");

總結:我們一般創建字符輸入或者輸出流一般情況下使用系統默認的碼表就可以,

如果來來回回需要指定碼表的話,就顯得非常的麻煩了

(將以上創建方式繼續簡化)

如果采用剛才的方式,創建對象寫起來比較復雜。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));

為了簡化這種操作,java就針對這兩個轉換的字符流提供其子類。

FileReader

FileWriter

它們的默認編碼是采用系統編碼。

構造學習:

FileWriter(File file)

FileWriter(String fileName)

FileReader(File file)

FileReader(String fileName)


flush()和close()的區別?

A:flush刷新緩沖區,流對象可以繼續

B:close先刷新緩沖區,再關閉流對象。流對象不可以繼續使用了。


練習:給字符輸出流裏面利用方法寫數據


字符輸出流操作步驟:

A:創建字符輸出流對象

B:調用寫數據方法

C:釋放資源

寫數據方法:

一次寫一個字符 write(int c)

一次寫一個字符數組write(char[] cbuf)

一次寫一個字符數組的一部分write(char[] cbuf, int off,int len)

一次寫一個字符串write(String str)

一次寫一個字符串的一部分write(String str,int off,int len)


字符輸入流

字符輸入流操作步驟:

A:創建字符輸入流對象

FileReader fr = new FileReader("a.txt");

B:讀取數據並顯示在控制臺

a:一次讀取一個字符

一次讀取一個字符

int ch;

while ((ch = fr.read()) != -1) {

System.out.print((char) ch);

}

b:一次讀取一個字符數組

char[] chs = new char[1024];

int len;

while ((len = fr.read(chs)) != -1) {

System.out.print(new String(chs, 0, len));

}

C:釋放資源

fr.close();


練習

註意:字符流輸入輸出流復制的文件是有要求的,簡單來說只要是記事本打開文件的內容你能夠看得懂,

就可以用字符流來進行復制,否則不行


具體原因:像復制MP3或者一些視頻文件的時候,如果他的字節個數不是偶數的話,就會造成文件的缺損,

因為一個字符等於兩個字節


1.利用字符流復制java文件(兩種方式,一次讀寫一個字符,一次讀寫一個字符數組)



高效流:(重要)

直接來一個例子

給文件中寫入十個"helloworld",每寫一個換一行,每寫一行必須寫入一個換行符“\r\n”

這樣寫的弊端,windows系統下的換行符是“\r\n”,Linux是"\n",Mac是"\r",這樣會造成代碼的通用性不強



按步驟寫代碼,核心代碼如下:

//1.創建字符高效輸出流,並指向一個txt文件

BufferedWriter bw = new BufferedWriter(new FileWriter("f.txt"));

//2.調用裏面寫數據的方法,給文件中寫入數據

for (int i = 0; i < 10; i++) {

//給文件中寫入helloworld

bw.write("helloworld");

//寫入換行符

bw.newLine();

//刷新緩沖區

bw.flush();

}

//關流

bw.close();

}

BufferedReader:字符緩沖輸入流

構造:BufferedReader(Reader in)

特殊方法:public String readLine():包含該行內容的字符串,不包含任何行終止符,如果已到達流末尾,則返回 null

BufferedWriter:字符緩沖輸出流

構造:BufferedWriter(Writer out)

特殊方法:public void newLine():會根據系統來確定寫入不同的換行符



最終練習:

復制文本文件:

4種

基本字符流一次讀寫一個字符

基本字符流一次讀寫一個字符數組

高效字符流一次讀寫一個字符

高效字符流一次讀寫一個字符數組

數據源:

a.txt

目的地:

b.txt


創建一個test類,實現以上四個要求(代碼復制來自我的elipse,運行輸出均無誤)

public class Test {

public static void main(String[] args) throws IOException {

method();//基本字符流一次讀寫一個字符

method2();//基本字符流一次讀寫一個字符數組

method3();//高效字符流一次讀寫一個字符

method4();//高效字符流一次讀寫一個字符數組

}


private static void method4() throws IOException {

//高效字符流一次讀寫一個字符數組

BufferedReader br = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bw = new BufferedWriter(new FileWriter("j.txt"));

//一次讀寫一個字符數組

char[] chs = new char[1024];

int len;

while ((len = br.read(chs))!=-1) {

bw.write(chs, 0, len);

bw.flush();

}

//釋放資源

bw.close();

br.close();

}


private static void method3() throws IOException {

//高效字符流一次讀寫一個字符

BufferedReader br = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bw = new BufferedWriter(new FileWriter("j.txt"));

//一次讀寫一個字符

int ch;

while ((ch=br.read())!=-1) {

bw.write(ch);

bw.flush();

}

//關流

bw.close();

br.close();

}


private static void method2() throws IOException {

//基本字符流一次讀寫一個字符數組

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("j.txt");

//一次讀寫一個字節數組

char[] chs = new char[1024];

int len;

while ((len = fr.read(chs))!=-1) {

fw.write(chs, 0, len);

fw.flush();

}

//關流

fw.close();

fr.close();

}


private static void method() throws IOException {

//基本字符流一次讀寫一個字符

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("j.txt");

//一次讀取一個字符,返回的是該字符對應的int值

/*System.out.println((char)fr.read());

System.out.println((char)fr.read());

System.out.println((char)fr.read());

System.out.println((char)fr.read());

System.out.println((char)fr.read());

*/

int ch;

while ((ch=fr.read())!=-1) {

//System.out.println((char)ch);

fw.write(ch);

fw.flush();

}

//釋放資源

fr.close();

fw.close();

}


}


倆個比較重要的東西

BufferedReader:字符緩沖輸入流

BufferedWriter:字符緩沖輸出流

的特性。


1.需求:向文件中寫入十個中國好,每寫一個換一行(普通方式實現,高效流輸出流特性實現)

2.利用字符高效流的一次讀寫一行的特性復制文件

寫數據註意三部曲:

bw.write(line);

bw.newLine();

bw.flush();


IO流練習

1.鍵盤錄入數據並存儲

鍵盤錄入5個學生信息(姓名,語文成績,數學成績,英語成績),按照總分從高到低存入文本文件

分析:

A:定義學生類

B:創建集合,采用TreeSet集合,並按照比較器排序

C:鍵盤錄入5個學生信息並存入集合

D:遍歷集合,並把數據寫到文本文件


代碼測試類如下,(之前需要一個學生類,自動生成即可,這裏不再多說)

public class StudentTest {

public static void main(String[] args) throws IOException {

//創建一個TreeSet集合,並寫一個比較器

TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {

@Override

public int compare(Student s1, Student s2) {

int num = s1.getAllScore() - s2.getAllScore();

int num2 = num==0?s1.getName().compareTo(s2.getName()):num;

return num2;

}

});

//鍵盤錄入5個學生信息

for (int i = 0; i < 5; i++) {

//創建鍵盤錄入對象

Scanner sc = new Scanner(System.in);

//接受鍵盤錄入數據

System.out.println("請輸入你的姓名");

String name = sc.nextLine();

System.out.println("請輸入你的語文成績");

int chinese = sc.nextInt();

System.out.println("請輸入你的數學成績");

int math = sc.nextInt();

System.out.println("請輸入你的英語成績");

int english = sc.nextInt();

//封裝成學生對象,存儲集合

Student s = new Student(name, chinese, math, english);

ts.add(s);

}

System.out.println("數據錄入完畢。。");

//遍歷集合,將集合中的數據全取不出來之後寫入文件中,每一個學生信息占一行

BufferedWriter bw = new BufferedWriter(new FileWriter("score.txt"));

for (Student s : ts) {

String info = s.getName()+" "+s.getChinese()+" "+s.getMath()+" "+s.getEnglish()+" "+s.getAllScore();

//將拼接成的字符串寫入文件中

bw.write(info);

bw.newLine();

bw.flush();

}

//釋放資源

bw.close();

io流是SE很重要的一部分,時常復習還是很重要的,代碼也得練。懂得原理就不會感到很難。


io流淺談