1. 程式人生 > >Java學習IO流(二)

Java學習IO流(二)

註意 latin 返回 編碼解碼 其中 sta 指定編碼 網絡 技術分享

字節流復制文件

原理:讀取一個已有的數據,並將這些讀取到的數據寫到另一個文件中

技術分享圖片

字節流通過單字節復制字節數組賦值

package com.oracle.demo01;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyDemo {
	public static void main(String[] args) throws IOException {
		//CopyDemo();
		Copy_2();
	}
    //字節流復制文件
	// 用字節去復制文件
	public static void CopyDemo() throws IOException {
		// 運行前獲取系統毫秒值
		long s = System.currentTimeMillis();
		// 數據源 往Java程序中讀數據
		FileInputStream fis = new FileInputStream("e:\\test\\a.jpg");
		// 目的地 從Java程序中往目的地復制,寫入
		FileOutputStream fos = new FileOutputStream("e:\\test\\a\\a.jpg");
		// 先獲取數據源信息read()
		int len = 0;
		while ((len = fis.read()) != -1) {
			// 讀取一個字節,就往目的地寫入一個字節
			fos.write(len);
		}
		fis.close();
		fos.close();
		// 運行後獲取系統毫秒值
		long v = System.currentTimeMillis();
		// 獲取運行的時間
		System.out.println(v - s);
	}

	// 用字節數組去復制文件
	public static void Copy_2() throws IOException {
		long s = System.currentTimeMillis();
		FileInputStream fis = new FileInputStream("e:\\test\\src.zip");
		// 目的地 從Java程序中往目的地復制,寫入
		FileOutputStream fos = new FileOutputStream("e:\\test\\a\\src.zip");
		// 先獲取數據源信息read()
		int len = 0;
		byte[] b = new byte[1024*1024];
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		fis.close();
		fos.close();
		long v = System.currentTimeMillis();
		System.out.println(v - s);
	}
}

字符流

通過字節流可以對數據進行讀寫操作,但是一旦數據中出現中文,就需要用到字符流通過字符編碼表對數據進行編碼與解碼

編碼表:其實就是生活中字符和計算機二進制的對應關系表。

1ascii: 一個字節中的7位就可以表示。對應的字節都是正數。0-xxxxxxx

2iso-8859-1:拉丁碼表 latin,用了一個字節用的8位。1-xxxxxxx 負數。

3GB2312:簡體中文碼表。包含6000-7000中文和符號。用兩個字節表示。兩個字節第一個字節是負數,第二個字節可能是正數

GBK:目前最常用的中文碼表,

2萬的中文和符號。用兩個字節表示,其中的一部分文字,第一個字節開頭是1,第二字節開頭是0

GB18030:最新的中文碼表,目前還沒有正式使用。

4、unicode:國際標準碼表:無論是什麽文字,都用兩個字節存儲。

Java中的char類型用的就是這個碼表。char c = ‘a‘;占兩個字節。

Java中的字符串是按照系統默認碼表來解析的。簡體中文版 字符串默認的碼表是GBK。

5UTF-8:基於unicode,一個字節就可以存儲數據,不要用兩個字節存儲,而且這個碼表更加的標準化,在每一個字節頭加入了編碼信息

(後期到api中查找)

能識別中文的碼表:GBKUTF-8;正因為識別中文碼表不唯一,涉及到了編碼解碼問題。

對於我們開發而言;常見的編碼 GBK UTF-8 ISO-8859-1

文字--->(數字) :編碼 “abc”.getBytes() byte[]

(數字)--->文字 : 解碼 byte[] b={97,98,99} new String(b)

字符輸入流Reader

Reader,讀取字符流的抽象超類

常用方法:

技術分享圖片

l read():讀取單個字符並返回

l read(char[]):將數據讀取到數組中,並返回讀取的個數。

Reader類之FileReader子類

構造方法:

技術分享圖片

字符輸出流Writer

Writer是寫入字符流的超類

常用的方法:

技術分享圖片

Writer類之FileWriter子類

構造方法:

技術分享圖片

package com.oracle.demo01;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
 * 字符流,專門針對於文本文件
 * 文本文件:就是用記事本打開這個文件,你能看懂的就叫文本文件
 * 除了文本文件,你都可以用字節流
 * 
 * 區分字節流和字符流
 * 類名中帶reader和writer都是字符流
 * 類名中帶Stream的都是字節流
 * */
public class WriteDemo {
	public static void main(String[] args) throws IOException {
		// read();
		// read2();
		// writer();
		copy();
	}

	public static void read() throws IOException {
		FileReader fr = new FileReader("e:\\test\\wenjian.txt");
		int len = 0;
		// read()方法一次只能讀一個字符,讀到末尾就返回-1
		while ((len = fr.read()) != -1) {
			System.out.print((char) len);
		}
		fr.close();
	}

	public static void read2() throws IOException {
		FileReader fr = new FileReader("e:\\test\\wenjian.txt");
		int len = 0;
		char[] ch = new char[1024];
		while ((len = fr.read(ch)) != -1) {
			System.out.print(new String(ch, 0, len));
		}
		fr.close();
	}

	public static void writer() throws IOException {
		FileWriter fw = new FileWriter("e:\\test\\wenjian.txt", true);
		// writer(int a)
		fw.write(100);
		fw.flush();// 刷新,調用write方法後,要刷新才能把字符刷進去
		fw.write("HelloWorld");
		fw.flush();// 刷新後,流還可以繼續使用
		char[] ch = { ‘L‘, ‘o‘, ‘v‘, ‘e‘, ‘j‘ };
		fw.write(ch);
		fw.close();// 具有刷新一次的功能,然後再關閉
	}

	public static void copy() throws IOException {
		// 數據源 讀取數據到Java程序
		FileReader fr = new FileReader("e:\\test\\wenjian.txt");
		// 目的地 從Java程序寫入目的地
		FileWriter fw = new FileWriter("e:\\test\\a\\wenjian.txt");
		int len = 0;
		char[] ch = new char[1024];
		while ((len = fr.read(ch)) != -1) {
			fw.write(ch, 0, len);
			fw.flush();
		}
		fr.close();
		fw.close();
	}
}

flush()close()的區別

技術分享圖片

flush():將流中的緩沖區緩沖的數據刷新到目的地中,刷新後,流還可以繼續使用

close():關閉資源,但在關閉前會將緩沖區中的數據先刷新到目的地,否則丟失數據,然後在關閉流。流不可以使用。如果寫入數據多,一定要一邊寫一邊刷新,最後一次可以不刷新,由close完成刷新並關閉。

轉換流

字符流對應的有字符編碼表,當需要指定編碼格式和緩沖區大小時,就需要用到轉換流InputStreamReader或者OutputStreamWriter

OutputStreamWriter 是字符流通向字節流的橋梁:可使用指定的字符編碼表,將要寫入流中的字符編碼成字節

它的作用的就是,將字符串按照指定的編碼表轉成字節,在使用字節流將這些字節寫出去

技術分享圖片

InputStreamReader 是字節流通向字符流的橋梁:它使用指定的字符編碼表讀取字節並將其解碼為字符

它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺默認的字符集。

技術分享圖片

package com.oracle.demo02;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class OutputStreamWriterDemo {
	public static void main(String[] args) throws IOException {
		method2();
	}

	// 轉換流的輸出流
	public static void method() throws IOException {
		FileOutputStream fos = new FileOutputStream("e:\\test\\d.txt",true);
		OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
		osw.write("你好");
		// 關閉流的時候,只要關閉最外一層就好了
		osw.close();
	}
	//轉換流的輸入流
	public static void method2() throws IOException{
		FileInputStream fis=new FileInputStream("e:\\test\\d.txt");
		InputStreamReader isr=new InputStreamReader(fis,"GBK");
		char[] ch=new char[1024];
		int len=0;
		while((len=isr.read(ch))!=-1){
			System.out.println(new String(ch,0,len));
		}
		isr.close();
	}
}

OutputStreamWriter流對象,它到底如何把字符轉成字節輸出的呢?

其實在OutputStreamWriter流中會有自己的緩沖區,當我們調用OutputStreamWriter對象的write方法時,會拿著字符到指定的碼表中進行查詢,把查到的字符編碼值轉成字節數存放到OutputStreamWriter緩沖區中。然後再調用刷新功能,或者關閉流,或者緩沖區存滿後會把緩沖區中的字節數據使用字節流寫到指定的文件中。

轉換流和子類的區別

發現有如下繼承關系:

OutputStreamWriter:

|--FileWriter:

InputStreamReader:

|--FileReader;

父類和子類的功能有什麽區別呢?

OutputStreamWriterInputStreamReader是字符和字節的橋梁:也可以稱之為字符轉換流。字符轉換流原理:字節流+編碼表

FileWriterFileReader:作為子類,僅作為操作字符文件的便捷類存在。當操作的字符文件,使用的是默認編碼表時可以不用父類,而直接用子類就完成操作了,簡化了代碼。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默認字符集。

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

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

這三句代碼的功能是一樣的,其中第三句最為便捷。

註意:一旦要指定其他編碼時,絕對不能用子類,必須使用字符轉換流。什麽時候用子類呢?

條件:

1、操作的是文件。2、使用默認編碼。

總結:

字節--->字符 : 看不懂的--->看的懂的。 需要讀。輸入流。 InputStreamReader

字符--->字節 : 看的懂的--->看不懂的。 需要寫。輸出流。 OutputStreamWriter

緩沖流

緩沖流的存在就是為了讀取大量的數據

字節緩沖流

1、寫入數據到流中,字節緩沖輸出流 BufferedOutputStream

2、讀取流中的數據,字節緩沖輸入流 BufferedInputStream

它們的內部都包含了一個緩沖區,通過緩沖區讀寫,就可以提高了IO流的讀寫速度

字節緩沖輸出流BufferedOutputStream

構造方法

public BufferedOutputStream(OutputStream out)創建一個新的緩沖輸出流,以將數據寫入指定的底層輸出流。

字節緩沖輸入流BufferedInputStream

構造方法

public BufferedInputStream(InputStream in)創建一個新的緩沖輸入流,讀取流中的數據

package com.oracle.demo03;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferDemo {
	public static void main(String[] args) throws IOException {
		read();
	}

	public static void write() throws IOException {
		long s = System.currentTimeMillis();
		// 字節輸出流
		FileOutputStream fos = new FileOutputStream("e:\\test\\java.txt");
		// 緩沖字節輸出流
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		bos.write(100);
		bos.close();
		long a = System.currentTimeMillis();
		System.out.println(a - s);
	}

	public static void read() throws IOException {
		long s = System.currentTimeMillis();
		// 字節輸出流
		FileInputStream fis = new FileInputStream("e:\\test\\java.txt");
		// 緩沖字節輸出流
		BufferedInputStream bis = new BufferedInputStream(fis);
		int len = 0;
		byte[] b = new byte[1024];
		while ((len = bis.read(b)) != -1) {
			System.out.println(new String(b, 0, len));
		}
		bis.close();
		long a = System.currentTimeMillis();
		System.out.println(a - s);
	}
}

 使用四種方式復制文件

package com.oracle.demo03;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo {
	public static void main(String[] args) throws IOException {
		// 數據源
		FileInputStream fis = new FileInputStream("d:\\eclipse.zip");
		// 目的地
		FileOutputStream fos = new FileOutputStream("e:\\test\\eclipse.zip");
		//copy1(fis, fos);
		//copy2(fis, fos);
		//copy3(fis, fos);
		copy4(fis, fos);

	}

	// 單個字節的復制
	public static void copy1(FileInputStream fis, FileOutputStream fos) throws IOException {
		long s = System.currentTimeMillis();
		// 獲取數據
		int len = 0;
		while ((len = fis.read()) != -1) {
			fos.write(len);
		}
		fis.close();
		fos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}

	// 字節數組的復制
	public static void copy2(FileInputStream fis, FileOutputStream fos) throws IOException {
		long s = System.currentTimeMillis();
		int len = 0;
		byte[] b = new byte[1024];
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		fis.close();
		fos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}

	// 字節緩沖流
	public static void copy3(FileInputStream fis, FileOutputStream fos) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		long s = System.currentTimeMillis();
		int len = 0;
		while ((len = bis.read()) != -1) {
			bos.write(len);
			bos.flush();
		}
		bis.close();
		bos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
    //字節數組緩沖流
	public static void copy4(FileInputStream fis, FileOutputStream fos) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		long s = System.currentTimeMillis();
		int len = 0;
		byte[] b = new byte[1024 * 1024];
		while ((len = bis.read(b)) != -1) {
			bos.write(b, 0, len);
			bos.flush();
		}
		bis.close();
		bos.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
}

字符緩沖流

1、 字符緩沖輸入流 BufferedReader

2、字符緩沖輸出流 BufferedWriter

完成文本數據的高效的寫入與讀取的操作

字符緩沖輸入流BufferedReader

將文本寫入字符輸出流,緩沖各個字符,從而提供單個字符、數組和字符串的高效寫入

方法:void newLine() 根據當前的系統,寫入一個換行符

字符緩沖輸出流BufferedWriter

從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。

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

/*
 * BufferedReader 字符緩沖輸入流
 * 
 * 方法:
 * 	String readLine() 
 * 需求:從文件中讀取數據,並顯示數據
 */
public class BufferedReaderDemo {
	public static void main(String[] args) throws IOException {
		//1,創建流
		BufferedReader in = new BufferedReader(new FileReader("file.txt"));
		//2,讀數據
		//一次一個字符
		//一次一個字符數組
		//一次讀取文本中一行的字符串內容
		String line = null;
		while( (line = in.readLine()) != null ){
			System.out.println(line);
		}
		
		//3,關閉流
		in.close();
	}
}

使用字符緩沖流進行文本文件的復制

package com.oracle.demo03;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Demo02 {
	public static void main(String[] args) throws IOException {
		copy4();

	}

	public static void copy1() throws IOException {
		// 數據源
		FileReader fr = new FileReader("d:\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\test\\eclipse.zip");
		int len = 0;
		while ((len = fr.read()) != -1) {
			fw.write(len);
			fw.flush();
		}
		fw.close();
		fr.close();
	}

	public static void copy2() throws IOException {
		// 數據源
		FileReader fr = new FileReader("d:\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\test\\eclipse.zip");
		int len = 0;
		char[] ch = new char[1024 * 1024];
		while ((len = fr.read(ch)) != -1) {
			fw.write(ch, 0, len);
			fw.flush();
		}
		fw.close();
		fr.close();
	}

	public static void copy3() throws IOException {
		// 數據源
		FileReader fr = new FileReader("d:\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\test\\eclipse.zip");
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		int len = 0;
		while ((len = br.read()) != -1) {
			bw.write(len);
			bw.flush();
		}
		bw.close();
		br.close();
	}

	public static void copy4() throws IOException {
		long s = System.currentTimeMillis();
		// 數據源
		FileReader fr = new FileReader("d:\\eclipse.zip");
		// 目的地
		FileWriter fw = new FileWriter("e:\\test\\eclipse.zip");
		BufferedReader br = new BufferedReader(fr);
		BufferedWriter bw = new BufferedWriter(fw);
		// int len = 0;
		// char[] ch = new char[1024 * 1024];
		// while ((len = br.read(ch)) != -1) {
		// bw.write(ch, 0, len);
		// bw.flush();
		// }

		String len = null;
		while ((len = br.readLine()) != null) {
			bw.write(len);
			bw.flush();
		}
		bw.close();
		br.close();
		long e = System.currentTimeMillis();
		System.out.println(e - s);
	}
}

流的操作規律

IO流中對象很多,解決問題(處理設備上的數據時)到底該用哪個對象呢?  

IO流進行了規律的總結(四個明確)

l 明確一:要操作的數據是數據源還是數據目的。

源:InputStream Reader

目的:OutputStream Writer

先根據需求明確要讀,還是要寫。

l 明確二:要操作的數據是字節還是文本呢?

源:

字節:InputStream

文本:Reader

目的:

字節:OutputStream

文本:Writer

已經明確到了具體的體系上。

l 明確三:明確數據所在的具體設備。

源設備:

硬盤:文件 File開頭。

內存:數組,字符串。

鍵盤:System.in;

網絡:Socket

目的設備:

硬盤:文件 File開頭。

內存:數組,字符串。

屏幕:System.out

網絡:Socket

完全可以明確具體要使用哪個流對象。

l 明確四:是否需要額外功能呢?

額外功能:

轉換嗎?轉換流。InputStreamReader OutputStreamWriter

高效嗎?緩沖區對象。BufferedXXX

InputStream

FileInputStream

BufferedInputStream

OuputStream

FileOutputStream

BufferedOuputStream

Writer

OutputStreamWriter

FileWriter

BufferedWriter

Reader

InputStreamReader

FileReader

BufferedReader

Java學習IO流(二)