1 轉(zhuǎn)換流
??在學(xué)習(xí)字符流(FileReader、FileWriter)的時(shí)候,其中說(shuō)如果需要指定編碼和緩沖區(qū)大小時(shí),可以在字節(jié)流的基礎(chǔ)上,構(gòu)造一個(gè)InputStreamReader或者OutputStreamWriter,這又是什么意思呢?
1.1 OutputStreamWriter類(lèi)
??查閱OutputStreamWriter的API介紹,OutputStreamWriter 是字符流通向字節(jié)流的橋梁:可使用指定的字符編碼表,將要寫(xiě)入流中的字符編碼成字節(jié)。它的作用的就是,將字符串按照指定的編碼表轉(zhuǎn)成字節(jié),在使用字節(jié)流將這些字節(jié)寫(xiě)出去。

TestDemo.java
package com.qtw.api;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class TestDemo {
public static void main(String[] args) throws IOException {
//創(chuàng)建與文件關(guān)聯(lián)的字節(jié)輸出流對(duì)象
FileOutputStream fos = new FileOutputStream("e:\\test\\b.txt");
//創(chuàng)建可以把字符轉(zhuǎn)成字節(jié)的轉(zhuǎn)換流對(duì)象,并指定編碼
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//調(diào)用轉(zhuǎn)換流,把文字寫(xiě)出去,其實(shí)是寫(xiě)到轉(zhuǎn)換流的緩沖區(qū)中
osw.write("你好");//寫(xiě)入緩沖區(qū)。
osw.close();
//gbk編碼,一個(gè)漢字對(duì)應(yīng)2個(gè)字節(jié);utf-8編碼,一個(gè)漢字對(duì)應(yīng)3個(gè)字節(jié)
}
}
??OutputStreamWriter流對(duì)象,它到底如何把字符轉(zhuǎn)成字節(jié)輸出的呢?
??其實(shí)在OutputStreamWriter流中維護(hù)自己的緩沖區(qū),當(dāng)我們調(diào)用OutputStreamWriter對(duì)象的write方法時(shí),會(huì)拿著字符到指定的碼表中進(jìn)行查詢(xún),把查到的字符編碼值轉(zhuǎn)成字節(jié)數(shù)存放到OutputStreamWriter緩沖區(qū)中。然后再調(diào)用刷新功能,或者關(guān)閉流,或者緩沖區(qū)存滿后會(huì)把緩沖區(qū)中的字節(jié)數(shù)據(jù)使用字節(jié)流寫(xiě)到指定的文件中。
1.2 InputStreamReader類(lèi)
??查閱InputStreamReader的API介紹,InputStreamReader 是字節(jié)流通向字符流的橋梁:它使用指定的字符編碼表讀取字節(jié)并將其解碼為字符。它使用的字符集可以由名稱(chēng)指定或顯式給定,或者可以接受平臺(tái)默認(rèn)的字符集。

TestDemo.java
package com.qtw.api;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class TestDemo {
public static void main(String[] args) throws IOException {
//創(chuàng)建讀取文件的字節(jié)流對(duì)象
FileInputStream in = new FileInputStream("e:\\test\\a.txt");
//創(chuàng)建轉(zhuǎn)換流對(duì)象
//InputStreamReader isr = new InputStreamReader(in);這樣創(chuàng)建對(duì)象,會(huì)用本地默認(rèn)碼表讀取,將會(huì)發(fā)生錯(cuò)誤解碼的錯(cuò)誤
InputStreamReader isr = new InputStreamReader(in,"utf-8");
//使用轉(zhuǎn)換流去讀字節(jié)流中的字節(jié)
int ch = 0;
while((ch = isr.read())!=-1){
System.out.println((char)ch);
}
//關(guān)閉流
isr.close();
}
}
注意:在讀取指定的編碼的文件時(shí),一定要指定編碼格式,否則就會(huì)發(fā)生解碼錯(cuò)誤,而發(fā)生亂碼現(xiàn)象
1.3 轉(zhuǎn)換流和子類(lèi)區(qū)別
發(fā)現(xiàn)有如下繼承關(guān)系:
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父類(lèi)和子類(lèi)的功能有什么區(qū)別呢?
??OutputStreamWriter和InputStreamReader是字符和字節(jié)的橋梁:也可以稱(chēng)之為字符轉(zhuǎn)換流。字符轉(zhuǎn)換流原理:字節(jié)流+編碼表。
??FileWriter和FileReader:作為子類(lèi),僅作為操作字符文件的便捷類(lèi)存在。當(dāng)操作的字符文件,使用的是默認(rèn)編碼表時(shí)可以不用父類(lèi),而直接用子類(lèi)就完成操作了,簡(jiǎn)化了代碼。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默認(rèn)字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
//這三句代碼的功能是一樣的,其中第三句最為便捷。
注意:一旦要指定其他編碼時(shí),絕對(duì)不能用子類(lèi),必須使用字符轉(zhuǎn)換流。
2 緩沖流
??在我們學(xué)習(xí)字節(jié)流與字符流的時(shí)候,大家都進(jìn)行過(guò)讀取文件中數(shù)據(jù)的操作,讀取數(shù)據(jù)量大的文件時(shí),讀取的速度會(huì)很慢,很影響我們程序的效率,那么,我想提高速度,怎么辦?Java中提高了一套緩沖流,它的存在,可提高IO流的讀寫(xiě)速度。緩沖流,根據(jù)流的分類(lèi)分為字節(jié)緩沖流與字符緩沖流。
2.1 字節(jié)緩沖流
字節(jié)緩沖流根據(jù)流的方向,共有2個(gè)
- 寫(xiě)入數(shù)據(jù)到流中,字節(jié)緩沖輸出流 BufferedOutputStream
- 讀取流中的數(shù)據(jù),字節(jié)緩沖輸入流 BufferedInputStream
它們的內(nèi)部都包含了一個(gè)緩沖區(qū),通過(guò)緩沖區(qū)讀寫(xiě),就可以提高了IO流的讀寫(xiě)速度
2.1.1 字節(jié)緩沖輸出流BufferedOutputStream
通過(guò)字節(jié)緩沖流,進(jìn)行文件的讀寫(xiě)操作 寫(xiě)數(shù)據(jù)到文件的操作
構(gòu)造方法
public BufferedOutputStream(OutputStream out)
TestDemo.java
package com.qtw.api;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;
public class TestDemo {
public static void main(String[] args) throws IOException {
/*
* 寫(xiě)數(shù)據(jù)到文件的方法
* 1,創(chuàng)建流
* 2,寫(xiě)數(shù)據(jù)
* 3,關(guān)閉流
*/
//創(chuàng)建基本的字節(jié)輸出流
FileOutputStream fileOut = new FileOutputStream("e:\\test\\abc.txt");
//使用高效的流,把基本的流進(jìn)行封裝,實(shí)現(xiàn)速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//2,寫(xiě)數(shù)據(jù)
out.write("hello".getBytes());
//3,關(guān)閉流
out.close();
}
}
2.1.2 字節(jié)緩沖輸入流 BufferedInputStream
讀取文件中數(shù)據(jù)的操作
構(gòu)造方法
public BufferedInputStream(InputStream in)
TestDemo.java
package com.qtw.api;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
public class TestDemo {
public static void main(String[] args) throws IOException {
/*
* 從文件中讀取數(shù)據(jù)
* 1,創(chuàng)建緩沖流對(duì)象
* 2,讀數(shù)據(jù),打印
* 3,關(guān)閉
*/
//1,創(chuàng)建緩沖流對(duì)象
FileInputStream fileIn = new FileInputStream("e:\\test\\abc.txt");
//把基本的流包裝成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//2,讀數(shù)據(jù)
int ch = -1;
while ( (ch = in.read()) != -1 ) {
//打印
System.out.print((char)ch);
}
//3,關(guān)閉
in.close();
}
}
2.1.3 使用基本的流與高效的流完成復(fù)制文件
??我們一直在說(shuō),高效的流速度快并高效,怎么體現(xiàn)呢?需要通過(guò)一個(gè)復(fù)制文件耗時(shí)的比較過(guò)程,來(lái)體驗(yàn)一下高效流帶來(lái)的快感。
TestDemo.java
package com.qtw.api;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
public class TestDemo {
/*
* 需求:將d:\\test.avi文件進(jìn)行復(fù)制
* 采用4種方式復(fù)制
* 方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制 共耗時(shí) 317304毫秒
* 方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值 共耗時(shí) 427毫秒
* 方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制 共耗時(shí) 568毫秒
* 方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值 共耗時(shí) 68毫秒
*
* 數(shù)據(jù)源: d:\\test.avi
* 目的地1: d:\\copy1.avi
* 目的地2: d:\\copy2.avi
* 目的地3: d:\\copy3.avi
* 目的地4: d:\\copy4.avi
*
* 實(shí)現(xiàn)的步驟:
* 1,指定數(shù)據(jù)源
* 2,指定目的地
* 3,讀數(shù)據(jù)
* 4,寫(xiě)數(shù)據(jù)
* 5,關(guān)閉流
*
*/
public static void main(String[] args) throws IOException {
//開(kāi)始計(jì)時(shí)
long start = System.currentTimeMillis();
//方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制
//method1("e:\\test\\dd.avi", "e:\\test\\dx.avi");
//方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值
//method2("e:\\test\\dd.avi", "e:\\test\\dx.avi");
//方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制
//method3("e:\\test\\dd.avi", "e:\\test\\dx.avi");
//方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值
method4("e:\\test\\dd.avi", "e:\\test\\dx.avi");
//結(jié)束計(jì)時(shí)
long end = System.currentTimeMillis();
//打印耗時(shí)多少毫秒
System.out.println("共耗時(shí) " +(end - start)+ "毫秒");
}
//方式4: 采用高效的流,一個(gè)多個(gè)字節(jié)的方式賦值
private static void method4(String src, String dest) throws IOException {
//1,指定數(shù)據(jù)源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,讀數(shù)據(jù)
byte[] buffer = new byte[1024];
int len = -1;
while ( (len = in.read(buffer)) != -1) {
//4,寫(xiě)數(shù)據(jù)
out.write(buffer, 0, len);
}
//5,關(guān)閉流
in.close();
out.close();
}
//方式3: 采用高效的流,一次一個(gè)字節(jié)的方式復(fù)制
private static void method3(String src, String dest) throws IOException {
//1,指定數(shù)據(jù)源
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
//2,指定目的地
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
//3,讀數(shù)據(jù)
int ch = -1;
while ((ch=in.read()) != -1) {
//4,寫(xiě)數(shù)據(jù)
out.write(ch);
}
//5,關(guān)閉流
in.close();
out.close();
}
//方式2: 采用基本的流,一個(gè)多個(gè)字節(jié)的方式賦值
private static void method2(String src, String dest) throws IOException {
//1,指定數(shù)據(jù)源
FileInputStream in = new FileInputStream(src);
//2,指定目的地
FileOutputStream out = new FileOutputStream(dest);
//3,讀數(shù)據(jù)
byte[] buffer = new byte[1024];
int len = -1;
while ( (len=in.read(buffer)) != -1) {
//4,寫(xiě)數(shù)據(jù)
out.write(buffer, 0, len);
}
//5,關(guān)閉流
in.close();
out.close();
}
//方式1: 采用基本的流,一次一個(gè)字節(jié)的方式復(fù)制
private static void method1(String src, String dest) throws IOException {
//1,指定數(shù)據(jù)源
FileInputStream in = new FileInputStream(src);
//2,指定目的地
FileOutputStream out = new FileOutputStream(dest);
//3,讀數(shù)據(jù)
int ch = -1;
while (( ch=in.read()) != -1) {
//4,寫(xiě)數(shù)據(jù)
out.write(ch);
}
//5,關(guān)閉流
in.close();
out.close();
}
}
2.2 字符緩沖流
字符緩沖輸入流 BufferedReader
字符緩沖輸出流 BufferedWriter
完成文本數(shù)據(jù)的高效的寫(xiě)入與讀取的操作
2.2.1 字符緩沖輸出流 BufferedWriter
將文本寫(xiě)入字符輸出流,緩沖各個(gè)字符,從而提供單個(gè)字符、數(shù)組和字符串的高效寫(xiě)入。
void newLine() 根據(jù)當(dāng)前的系統(tǒng),寫(xiě)入一個(gè)換行符
TestDemo.java
package com.qtw.api;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
/*
* BufferedWriter 字符緩沖輸出流
* 方法
* public void newLine()寫(xiě)入一個(gè)行分隔符
*
* 需求: 通過(guò)緩沖輸出流寫(xiě)入數(shù)據(jù)到文件
* 分析:
* 1,創(chuàng)建流對(duì)象
* 2,寫(xiě)數(shù)據(jù)
* 3,關(guān)閉流
*
*/
//創(chuàng)建流
//基本字符輸出流
FileWriter fileOut = new FileWriter("e:\\test\\file.txt");
//把基本的流進(jìn)行包裝
BufferedWriter out = new BufferedWriter(fileOut);
//2,寫(xiě)數(shù)據(jù)
for (int i=0; i<5; i++) {
out.write("hello");
out.newLine();
}
//3,關(guān)閉流
out.close();
}
}
2.2.2 字符緩沖輸入流 BufferedReader
從字符輸入流中讀取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。
public String readLine() 讀取一個(gè)文本行,包含該行內(nèi)容的字符串,不包含任何行終止符,如果已到達(dá)流末尾,則返回 null
TestDemo.java
package com.qtw.api;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
/*
* BufferedReader 字符緩沖輸入流
*
* 方法:
* String readLine()
* 需求:從文件中讀取數(shù)據(jù),并顯示數(shù)據(jù)
*/
//1,創(chuàng)建流
BufferedReader in = new BufferedReader(new FileReader("e:\\test\\file.txt"));
//2,讀數(shù)據(jù)
//一次一個(gè)字符
//一次一個(gè)字符數(shù)組
//一次讀取文本中一行的字符串內(nèi)容
String line = null;
while( (line = in.readLine()) != null ){
System.out.println(line);
}
//3,關(guān)閉流
in.close();
}
}
2.2.3 使用字符緩沖流完成文本文件的復(fù)制
剛剛我們學(xué)習(xí)完了緩沖流,現(xiàn)在我們就使用字符緩沖流的特有功能,完成文本文件的復(fù)制
TestDemo.java
package com.qtw.api;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
public class TestDemo {
public static void main(String[] args) throws IOException {
/*
* 采用高效的字符緩沖流,完成文本文件的賦值
*
* 數(shù)據(jù)源: file.txt
* 目的地: copyFile.txt
*
* 分析:
* 1,指定數(shù)據(jù)源, 是數(shù)據(jù)源中讀數(shù)據(jù),采用輸入流
* 2,指定目的地,是把數(shù)據(jù)寫(xiě)入目的地,采用輸出流
* 3,讀數(shù)據(jù)
* 4,寫(xiě)數(shù)據(jù)
* 5,關(guān)閉流
*/
//1,指定數(shù)據(jù)源, 是數(shù)據(jù)源中讀數(shù)據(jù),采用輸入流
BufferedReader in = new BufferedReader(new FileReader("e:\\test\\file.txt"));
//2,指定目的地,是把數(shù)據(jù)寫(xiě)入目的地,采用輸出流
BufferedWriter out = new BufferedWriter(new FileWriter("e:\\test\\copyFile.txt"));
//3,讀數(shù)據(jù)
String line = null;
while ( (line = in.readLine()) != null ) {
//4,寫(xiě)數(shù)據(jù)
out.write(line);
//寫(xiě)入換行符號(hào)
out.newLine();
}
//5,關(guān)閉流
out.close();
in.close();
}
}