流類總結

  • java內存中存的字符都是Unicode編碼的,當讀取磁盤中的文件的時候,默認通過GBK解碼(記事本的ANSI編碼,就是這種默認編碼),但是磁盤/網絡中有各種各樣的的編碼方式(比如:UTF-8,UTF-8是網頁比較流行的一種格式,但是它無法通過默認的GBK解碼,只能通過UTF-8進行解碼),因此從java內存到磁盤/網絡或者從磁盤/網絡到java內存中會有一個轉換過程,InputStreamReader和OutputStreamWriter可指定編碼格式
  • https://blog.csdn.net/m0_37732829/article/details/80571166
  • 將數據存到電腦中,最根本的格式是二進制的格式,但是當存入比如文檔中或者別的文件中的時候,會有自己的一個編碼格式,將二進制轉換成自己的編碼格式,當讀入到java程序中的時候,java又將他們自己的編碼格式變成Unicode編碼格式。當從java程序讀到別的文件中的時候,又將Unicode編碼格式轉換成其餘的編碼格式。
  • 做題的時候不需要想太多,比如需要一個String類型的,就用Buffered流,需要讀int類型的,就用Data流,需要讀結構體類型的,就用結構體類型的流。
  • 字符流的時候,write(String類型)一般文件中不會錯
  • 做題的時候,先想到底是讀/寫字節/字符進來,最終以什麼形式,然後再想各種形式之間的轉換問題。
  • 想要什麼類型,中間需要經過多少轉換要想清楚

一、輸入流和輸出流的四種抽象基本類是InputStream、OutputStream、Reader、Writer

輸入流和輸出流是相對於java內存而言的
輸入流(讀到java內存中):InputStream、Reader
輸出流(從java內存中讀出):OutputStream、Writer


(一)InputStream

直接子類有:FileInputStream, ObjectInputStream
間接子類有:BufferedInputStream(FileInputStream),DataInputStream(FileInputStream)

字節爲單位,通過默認編碼從磁盤/網絡中讀取文件到java內存中進行的操作

1、基本操作

read括號中沒有或者是byte[]類型,返回值是int類型

在這裏插入圖片描述


(二)Reader

直接子類有:BufferedReader, InputStreamReader
間接子類有:FileReader(InputStreamReader)

字符爲單位從磁盤/網絡中讀取文件到java內存中進行的操作

1、基本操作

read括號中沒有或者是char[]類型,返回值是int類型

在這裏插入圖片描述


(三)OutputStream

直接子類有:ObjectOutputStream、BufferedOutputStream
間接子類有:DataOutputStream, FileOutputStream

字節爲單位將java內存中的數據寫到磁盤/網絡中

1、基本操作

write括號中的是int或者byte[]類型,返回值是int類型,但是作用:將指定的字節寫入該輸出流中

在這裏插入圖片描述


(四)Writer

直接子類有:BufferedWriter, OutputStreamWriter
間接子類有:FileWriter, PrintWriter

字符爲單位將java內存中的數據寫到磁盤/網絡中

1、基本操作

write括號中的是int或者char[]或者String類型,返回值是void類型

在這裏插入圖片描述


二、文件輸入流和輸出流的四種基本類是FileInputStream、FileOutputStream、FileReader、FileWriter

輸入流和輸出流是相對於java內存而言的
輸入流(讀到java內存中):FileInputStream、FileReader
輸出流(從java內存中讀出):FileOutputStream、FileWriter


(一)FileInputStream(以字節的形式讀入char,輸出也要爲char)

FileInputStream in=null;//可能會拋出一個已檢查異常//別忘記導入包
try
	{
		in=new FileInputStream("TestFileInputStream.java");
	}
	catch(FileNotFoundException e)
	{
		System.out.println("找不到指定文件");
		System.exit(-1);//直接退出程序
	}
	try
	{
		ong num=0;
		while((b=in.read())!=-1)//每次讀一個字節給b,-1的意思是已經讀到文件結尾了
		{
			System.out.print((char)b);//讀入char,輸出也要爲char//read的返回值是int類型的
			num++;//統計多少個字節
		}
		System.out.println();
		System.out.println("共讀取了"+num+"個字節");
	}
  • read()返回類型是int,結果爲-1代表讀到結尾了
  • 因爲讀的時候是按照字節來讀的,所以輸出的時候需要強制轉換成char類型的

(二)FileReader(以字符的形式讀入char,輸出也要爲char)

FileReader fr=null;//可能會拋出一個已檢查異常//別忘記導入包
int c=0;
try
{
	fr=new FileReader("E:\\workplace\\KeJian\\src\\TestFileReader.java");
	int ln=0;
	while((c=fr.read())!=-1)//沒有讀到文件結尾
	{
		System.out.print((char)c);//讀入char,輸出也要爲char
		ln++;
	}
	System.out.println("共讀取了"+ln+"個字符");
}
  • read()返回類型是int,結果爲-1代表讀到結尾了
  • 因爲讀的時候是按照字節來讀的,所以輸出的時候需要強制轉換成char類型的

(三)FileOutputStream(以字節的形式寫到磁盤中)

  • 如果通過FileInputStream讀入,那麼就需要用FileOutputStream與其相匹配,如果用FileWriter,會導致中文輸出不正常,因爲按照字節讀入,就要按照字節輸出,不能按照字符輸出,否則會導致亂碼。
  • 如果通過FileInputStream讀入,FileOutputStream與其相匹配輸出到文件中的時候,不需要必須爲char類型,因爲讀入和輸出的方式(以字節爲單位)相同
FileInputStream in=null;//可能會拋出一個已檢查異常//別忘記導入包
FileOutputStream out=null;
FileWriter f=null;
try
{
	in=new FileInputStream("HelloWorld.java");
	out=new FileOutputStream("newHello.java");
	while((b=in.read())!=-1)
	{
		out.write(b);//中文正常//讀完之後,寫到newHello.java這個文件中去
	}
}

(四)FileWriter(以字符的形式寫到磁盤)

FileWriter fw=null;//可能會拋出一個已檢查異常//別忘記導入包
FileOutputStream fs=null;
try
	{
		fw=new FileWriter("E:\\workplace\\KeJian\\unicode.txt");//雙斜槓是轉移符的問題,\\代表\
		fs=new FileOutputStream("E:\\workplace\\KeJian\\unicode1.txt");
		for(int c=0;c<=50;c++)
		{
			fw.write(c);//亂碼
			fs.write(c);//亂碼
		}
	}
  • 都是亂碼的原因是:需要的是字符/字節,但是傳進來的是int不是一個字節/字符,所以會導致亂碼
  • 可能會想,爲什麼前面從文件中讀取完之後是int類型直接寫到文件中卻不是亂碼呢?因爲即使是int類型,也是從文件中按照字節/字符的形式讀取,按照字節/字符的形式拷貝的,因此不是亂碼,這裏是直接把一個int類型的數字放進去,不是字節/字符形式,必然會出現亂碼的問題

三、字符處理流


(一)BufferedInputStream(字節流)
括號中需要是InputStream的子類
直接子類有:FileInputStream, ObjectInputStream
間接子類有:BufferedInputStream(FileInputStream),DataInputStream(FileInputStream)

BufferedInputStream bis=null;
try
	{
		/*FileInputStream fis=new FileInputStream("HelloWorld.java");
		bis=new BufferedInputStream(fis);*/
		bis=new BufferedInputStream(new FileInputStream("HelloWorld.java"));
		int c=0;
		for(int i=0;(c=bis.read())!=-1;i++)
		{
			System.out.print((char)c);
		}
	}
  • 與 FileInputStream相比,沒有太大的區別,僅僅是加快了速度
  • BufferedInputStream括號中只能new FileInputStream,別的不行
    在這裏插入圖片描述

(二)BufferedReader(字符流)
括號中需要是Reader的子類
直接子類有:BufferedReader, InputStreamReader
間接子類有:FileReader(InputStreamReader)

  • 作用:緩衝字符,以便提供字符、數組和行的有效讀取
  • BufferedReader中能new FileReader,new InputStreamReader
  • 增加了readLine方法,返回值是String類型,比較好用,一次讀取一行,因此,如果想要讀取String類型的數據,就用BufferedReader

在這裏插入圖片描述

br=new BufferedReader(new FileReader("test.txt"));//讀test.txt中的內容
String s=null;
while((s=br.readLine())!=null)
{
	System.out.println(s);
}

(三)BufferedOutputStream(字節流)
括號中需要是OutputStream的子類
直接子類有:ObjectOutputStream
間接子類有: DataOutputStream,FileOutputStream

在這裏插入圖片描述


(四)BufferedWriter(字符流)
括號中只能是Writer的子類
直接子類有:BufferedWriter, OutputStreamWriter
間接子類有: FileWriter, PrintWriter

  • 作用:緩衝字符,以便提供字符、數組和行的有效讀取
  • BufferedWriter中 能new FileWriter 能new OutputStreamWriter
  • 增加了newLine方法,比較好用,每次寫完一行之後,自動換行,因此,如果想要讀完一行之後回車,就用BufferedWriter
    在這裏插入圖片描述

四、轉換流

(一)InputStreamReader(字符流)
括號中只能是InputStream的子類,可以指定用何種形式編碼

  • InputStreamReader是 InputStream中的字節轉換成字符
  • 爲什麼要指定編碼集合呢?
    因爲java程序在內存中的字符都是Unicode編碼的,但是從文件中讀取的內容有自己的編碼格式,可能是jbk編碼,可能是ISO8859_1編碼,還有可能是ASCILL編碼,編碼不同,所以要根據已有編碼轉換成Unicode編碼,因此,要告訴java原來是什麼樣的編碼格式(但是如果指定編碼格式錯誤的話,會出現亂碼問題)。
  • 只能new InputStream的子類,如:FileInputStream

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

FileWriter和FileOutputStream都可以實現在文章結尾繼續寫東西而不是覆蓋掉以前的東西,至於true加到哪裏上面的兩張圖片已經說的很清楚了。

InputStreamReader isr=null;
try
{
	isr=new InputStreamReader(new FileInputStream("TestTileInputStream.java"));//通過InputStreamReader讀取FileInputStream中讀取的TestTileInputStream.java中的字符
	long num=0;
	while((b=isr.read())!=-1)
	{
		System.out.print((char)b);
		num++;
	}
	System.out.println("共讀取了"+num+"個字符");
}

將鍵盤輸入的內容直接輸入到文檔中

String s;
InputStreamReader isr=new InputStreamReader(System.in);
/*
 * 本來應該套一個InputStream,但是套了System.in
 * 所以System.in也是InputStream類型的
 * 所以可以傳給InputStreamReader
 * InputStreamReader套接了控制檯鍵盤輸入
 * System.in讀入的是字節,InputStreamReader轉換成了字符
 * InputStreamReader只能一個字符一個字符地讀,比較麻煩,所以又套接了一個BufferedReader
* */
BufferedReader br=new BufferedReader(isr);//BufferedReader的特點,能一次讀取一行
System.out.println("Unix:Type ctrl-d or cril-c to exit."+"\nWindows:Type ctrl-z to exit");
try
{
	//用Ctrl+z來結束
	while((s=br.readLine())!=null)
	{
		System.out.println("Read: "+s);//輸入一行,打印一行
	}
}

(二)OutputStreamWriter(字符流)
括號中只能是OutputStream的子類,可以指定編碼格式

  • OutputStreamWriter是 OutputStream中的字節轉換成字符
  • 爲什麼要指定編碼集合呢?
    因爲java程序在內存中的字符都是Unicode編碼的,到文件中的時候,會有自己的編碼格式,可能是jbk編碼,可能是ISO8859_1編碼,還有可能是ASCILL編碼,編碼不同,所以要將Unicode編碼轉換成自己想要的編碼格式,因此,要告訴java自己需要什麼樣的編碼格式。
  • 只能new OutputStream的子類,如:FileOutputStream

在這裏插入圖片描述

try
{
	OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("transform1.txt"));//通過FileOutputStream文件輸出流,往transform1.txt中寫數據
	osw.write("計算機學院");
	osw.write("SUN Java");
	System.out.println(osw.getEncoding());//寫入的時候沒有指定編碼格式,那麼就採用中文Window默認編碼GBK
	osw.close();//FileOutputStream構造方法第二個參數的含義,是否追加
	osw=new OutputStreamWriter(new FileOutputStream("transform1.txt",true),"ISO8859_1");
	/*這裏用FileOutputStream的重載方法,形參加了個true
	 * 這裏本來默認是false,每次寫的時候,會覆蓋原來文件的內容
	 * 但是加了true,意思是保留原有文件內容,並且在原有文件的尾部追加新的內容
	* 編碼格式改成IS08859_1,指的是英文字符,沒有中文字符串
	 * lantin-1
	 * */
	osw.write("山東科技大學");//上面指定的編碼格式中,沒有文字字符串
	osw.write("C#");
	System.out.println(osw.getEncoding());
	sw.close();
}

在這裏插入圖片描述

  • ISO8859_1編碼格式中沒有文字字符串,所以是錯誤的。
  • osw=new OutputStreamWriter(new FileOutputStream(“transform1.txt”,true),“ISO8859_1”);
    /*這裏用FileOutputStream的重載方法,形參加了個true
    * 這裏本來默認是false,每次寫的時候,會覆蓋原來文件的內容
    * 但是加了true,意思是保留原有文件內容,並且在原有文件的尾部追加新的內容
    * 編碼格式改成IS08859_1,指的是英文字符,沒有中文字符串
    * lantin-1
    * */
    在這裏插入圖片描述

五、數據流

(一)DataInputStream(字節流)
括號內只能是InputStream的子類

  • 可以直接將字節類型的轉換爲基本類型數據
    在這裏插入圖片描述

(二)DataOutputStream(字節流)
括號內只能是OutputStream的子類

  • 可以直接將字節類型的轉換爲基本類型數據
  • 將基本類型轉換爲字節存起來

在這裏插入圖片描述


六、Print流

(一)PrintStream(字節流)

在這裏插入圖片描述

在這裏插入圖片描述

PrintStream ps=null;
try
{
	FileOutputStream fos=new FileOutputStream("redirect.txt");
	ps=new PrintStream(fos,true,"utf-8");
	/*
	 * PrintStream中有構造方法,可以有三個參數的構造方法
	 * 第一個創建一個OutputStream
	* 第二個是是不是自動的刷新、緩衝、清空
	* 第三個指定輸出的字符是什麼編碼格式
	 * */
	if(ps!=null)
	{
		System.setOut(ps);//實現輸出的重定向,不再向控制檯輸出,而是向指定文件中輸出
	}
			
			int line=0;
			for(char c=100;c<=200;c++)
			{
				System.out.println();//此時通過FileOutputStream這個流往redirect.txt這個文件中輸出
				line=0;
			}
		}
  • System.setOut(ps);可以實現重定向

(二)PrintWriter(字符流)

在這裏插入圖片描述
在這裏插入圖片描述


對象序列化

爲什麼要進行對象序列化呢?
目的是爲了轉化成字節序列,便於存盤或者是進行網絡傳輸。存盤和網絡傳輸的是以字節爲單位,對象序列化之後,就不會考慮到編碼差異等問題了。

1、想要被對象序列化,就必須要實現Serializable或者Externalizable兩個接口中的某一個

2、Serializable這個接口中沒有任何接口,無需實現任何方法,僅僅繼承這個接口就好。

3、使對象序列化的流
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章