字節(jié)流與字符流
先來看一下流的概念:
在程序中所有的數(shù)據(jù)都是以流的方式進(jìn)行傳輸或保存的,,程序需要數(shù)據(jù)的時(shí)候要使用輸入流讀取數(shù)據(jù),,而當(dāng)程序需要將一些數(shù)據(jù)保存起來的時(shí)候,就要使用輸出流完成,。
程序中的輸入輸出都是以流的形式保存的,,流中保存的實(shí)際上全都是字節(jié)文件。
字節(jié)流與字符流
在java.io包中操作文件內(nèi)容的主要有兩大類:字節(jié)流,、字符流,,兩類都分為輸入和輸出操作。在字節(jié)流中輸出數(shù)據(jù)主要是使用OutputStream完成,,輸入使的是InputStream,,在字符流中輸出主要是使用Writer類完成,輸入流主要使用Reader類完成,。(這四個(gè)都是抽象類)
java中提供了專用于輸入輸出功能的包Java.io,其中包括:
InputStream,OutputStream,Reader,Writer
InputStream 和OutputStream,兩個(gè)是為字節(jié)流設(shè)計(jì)的,主要用來處理字節(jié)或二進(jìn)制對(duì)象,
Reader和 Writer.兩個(gè)是為字符流(一個(gè)字符占兩個(gè)字節(jié))設(shè)計(jì)的,主要用來處理字符或字符串.
字符流處理的單元為2個(gè)字節(jié)的Unicode字符,,分別操作字符、字符數(shù)組或字符串,,而字節(jié)流處理單元為1個(gè)字節(jié),,操作字節(jié)和字節(jié)數(shù)組。所以字符流是由Java虛擬機(jī)將字節(jié)轉(zhuǎn)化為2個(gè)字節(jié)的Unicode字符為單位的字符而成的,,所以它對(duì)多國(guó)語言支持性比較好,!如果是音頻文件、圖片,、歌曲,,就用字節(jié)流好點(diǎn),如果是關(guān)系到中文(文本)的,,用字符流好點(diǎn)
所有文件的儲(chǔ)存是都是字節(jié)(byte)的儲(chǔ)存,,在磁盤上保留的并不是文件的字符而是先把字符編碼成字節(jié),再儲(chǔ)存這些字節(jié)到磁盤,。在讀取文件(特別是文本文件)時(shí),,也是一個(gè)字節(jié)一個(gè)字節(jié)地讀取以形成字節(jié)序列
字節(jié)流可用于任何類型的對(duì)象,,包括二進(jìn)制對(duì)象,而字符流只能處理字符或者字符串,; 2. 字節(jié)流提供了處理任何類型的IO操作的功能,,但它不能直接處理Unicode字符,而字符流就可以
字節(jié)流是最基本的,,所有的InputStrem和OutputStream的子類都是,主要用在處理二進(jìn)制數(shù)據(jù),,它是按字節(jié)來處理的 但實(shí)際中很多的數(shù)據(jù)是文本,又提出了字符流的概念,,它是按虛擬機(jī)的encode來處理,,也就是要進(jìn)行字符集的轉(zhuǎn)化 這兩個(gè)之間通過 InputStreamReader,OutputStreamWriter來關(guān)聯(lián),實(shí)際上是通過byte[]和String來關(guān)聯(lián) 在實(shí)際開發(fā)中出現(xiàn)的漢字問題實(shí)際上都是在字符流和字節(jié)流之間轉(zhuǎn)化不統(tǒng)一而造成的
==================我們還可以看到:============
Reader類的read()方法返回類型為int :作為整數(shù)讀取的字符(占兩個(gè)字節(jié)共16位),,范圍在
0 到 65535 之間 (0x00-0xffff),,如果已到達(dá)流的末尾,則返回 -1
inputStream的read()雖然也返回int,,但由于此類是面向字節(jié)流的,,一個(gè)字節(jié)占8個(gè)位,所以返回 0 到 255 范圍內(nèi)的 int 字節(jié)值,。如果因?yàn)橐呀?jīng)到達(dá)流末尾而沒有可用的字節(jié),,則返回值 -1。因此對(duì)于不能用0-255來表示的值就得用字符流來讀??!比如說漢字.
操作流程
在Java中IO操作也是有相應(yīng)步驟的,以文件操作為例,,主要的操作流程如下:
1 使用File類打開一個(gè)文件
2 通過字節(jié)流或字符流的子類,,指定輸出的位置
3 進(jìn)行讀/寫操作
4 關(guān)閉輸入/輸出
IO操作屬于資源操作,一定要記得關(guān)閉
字節(jié)流
字節(jié)流主要是操作byte類型數(shù)據(jù),,以byte數(shù)組為準(zhǔn),,主要操作類就是OutputStream、InputStream
字節(jié)輸出流:OutputStream
OutputStream是整個(gè)IO包中字節(jié)輸出流的最大父類,,此類的定義如下:
public abstract class OutputStream extends Object implements Closeable,Flushable
從以上的定義可以發(fā)現(xiàn),,此類是一個(gè)抽象類,如果想要使用此類的話,,則首先必須通過子類實(shí)例化對(duì)象,,那么如果現(xiàn)在要操作的是一個(gè)文件,則可以使用:FileOutputStream類,。通過向上轉(zhuǎn)型之后,,可以為OutputStream實(shí)例化
Closeable表示可以關(guān)閉的操作,因?yàn)槌绦蜻\(yùn)行到最后肯定要關(guān)閉
Flushable:表示刷新,,清空內(nèi)存中的數(shù)據(jù)
FileOutputStream類的構(gòu)造方法如下:
public FileOutputStream(File file)throws FileNotFoundException
寫數(shù)據(jù):
1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f);//如果文件不存在會(huì)自動(dòng)創(chuàng)建
10 String str="Hello World";
11 byte[] b=str.getBytes();
12 out.write(b);//因?yàn)槭亲止?jié)流,,所以要轉(zhuǎn)化成字節(jié)數(shù)組進(jìn)行輸出
13 out.close();
14 }
15 }
也可以一個(gè)字節(jié)一個(gè)字節(jié)進(jìn)行輸出,,如下:
1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f);//如果文件不存在會(huì)自動(dòng)創(chuàng)建
10 String str="Hello World";
11 byte[] b=str.getBytes();
12 for(int i=0;i<b.length;i++){
13 out.write(b[i]);
14 }
15 out.close();
16 }
17 }
以上輸出只會(huì)進(jìn)行覆蓋,如果要追加的話,,請(qǐng)看FileOutputStream類的另一個(gè)構(gòu)造方法:
public FileOutputStream(File file,boolean append)throws FileNotFoundException
在構(gòu)造方法中,如果將append的值設(shè)置為true,,則表示在文件的末尾追加內(nèi)容,。
1 import java.io.File;
2 import java.io.FileOutputStream;
3 import java.io.IOException;
4 import java.io.OutputStream;
5
6 public class Test11 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 OutputStream out=new FileOutputStream(f,true);//追加內(nèi)容
10 String str="\r\nHello World";
11 byte[] b=str.getBytes();
12 for(int i=0;i<b.length;i++){
13 out.write(b[i]);
14 }
15 out.close();
16 }
17 }
文件中換行為:\r\n
字節(jié)輸入流:InputStream
既然程序可以向文件中寫入內(nèi)容,則就可以通過InputStream從文件中把內(nèi)容讀取進(jìn)來,,首先來看InputStream類的定義:
public abstract class InputStream extends Object implements Closeable
與OutputStream類一樣,,InputStream本身也是一個(gè)抽象類,必須依靠其子類,,如果現(xiàn)在是從文件中讀取,,就用FileInputStream來實(shí)現(xiàn)。
觀察FileInputStream類的構(gòu)造方法:
public FileInputStream(File file)throws FileNotFoundException
讀文件:
1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test12 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[1024];
11 int len=in.read(b);
12 in.close();
13 System.out.println(new String(b,0,len));
14 }
15 }
但以上方法是有問題的,,用不用開辟這么大的一個(gè)字節(jié)數(shù)組,,明顯是浪費(fèi)嘛,我們可以根據(jù)文件的大小來定義字節(jié)數(shù)組的大小,,File類中的方法:public long length()
1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test13 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[(int) f.length()];
11 in.read(b);
12 in.close();
13 System.out.println(new String(b));
14 }
15 }
我們換種方式,,一個(gè)字節(jié)一個(gè)字節(jié)讀入~
1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test14 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[(int) f.length()];
11 for(int i=0;i<b.length;i++){
12 b[i]=(byte) in.read();
13 }
14 in.close();
15 System.out.println(new String(b));
16 }
17 }
但以上情況只適合知道輸入文件的大小,不知道的話用如下方法:
1 import java.io.File;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class Test15 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 InputStream in=new FileInputStream(f);
10 byte[] b=new byte[1024];
11 int temp=0;
12 int len=0;
13 while((temp=in.read())!=-1){//-1為文件讀完的標(biāo)志
14 b[len]=(byte) temp;
15 len++;
16 }
17 in.close();
18 System.out.println(new String(b,0,len));
19 }
20 }
字符流
在程序中一個(gè)字符等于兩個(gè)字節(jié),,那么java提供了Reader,、Writer兩個(gè)專門操作字符流的類。
字符輸出流:Writer
Writer本身是一個(gè)字符流的輸出類,,此類的定義如下:
public abstract class Writer extends Object implements Appendable,,Closeable,,Flushable
此類本身也是一個(gè)抽象類,,如果要使用此類,則肯定要使用其子類,,此時(shí)如果是向文件中寫入內(nèi)容,,所以應(yīng)該使用FileWriter的子類,。
FileWriter類的構(gòu)造方法定義如下:
public FileWriter(File file)throws IOException
字符流的操作比字節(jié)流操作好在一點(diǎn),就是可以直接輸出字符串了,,不用再像之前那樣進(jìn)行轉(zhuǎn)換操作了,。
寫文件:
1 import java.io.File;
2 import java.io.FileWriter;
3 import java.io.IOException;
4 import java.io.Writer;
5
6 public class Test16 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Writer out=new FileWriter(f);
10 String str="Hello World";
11 out.write(str);
12 out.close();
13 }
14 }
在默認(rèn)情況下再次輸出會(huì)覆蓋,追加的方法也是在構(gòu)造函數(shù)上加上追加標(biāo)記
1 import java.io.File;
2 import java.io.FileWriter;
3 import java.io.IOException;
4 import java.io.Writer;
5
6 public class Test17 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Writer out=new FileWriter(f,true);//追加
10 String str="\r\nHello World";
11 out.write(str);
12 out.close();
13 }
14 }
字符輸入流:Reader
Reader是使用字符的方式從文件中取出數(shù)據(jù),,Reader類的定義如下:
public abstract class Reader extends Objects implements Readable,,Closeable
Reader本身也是抽象類,如果現(xiàn)在要從文件中讀取內(nèi)容,,則可以直接使用FileReader子類,。
FileReader的構(gòu)造方法定義如下:
public FileReader(File file)throws FileNotFoundException
以字符數(shù)組的形式讀取出數(shù)據(jù):
1 import java.io.File;
2 import java.io.FileReader;
3 import java.io.IOException;
4 import java.io.Reader;
5
6 public class Test18 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Reader input=new FileReader(f);
10 char[] c=new char[1024];
11 int len=input.read(c);
12 input.close();
13 System.out.println(new String(c,0,len));
14 }
15 }
也可以用循環(huán)方式,,判斷是否讀到底:
1 import java.io.File;
2 import java.io.FileReader;
3 import java.io.IOException;
4 import java.io.Reader;
5
6 public class Test19 {
7 public static void main(String[] args) throws IOException {
8 File f = new File("d:" + File.separator+"test.txt");
9 Reader input=new FileReader(f);
10 char[] c=new char[1024];
11 int temp=0;
12 int len=0;
13 while((temp=input.read())!=-1){
14 c[len]=(char) temp;
15 len++;
16 }
17 input.close();
18 System.out.println(new String(c,0,len));
19 }
20 }
字節(jié)流與字符流的區(qū)別
字節(jié)流和字符流使用是非常相似的,那么除了操作代碼的不同之外,,還有哪些不同呢,?
字節(jié)流在操作的時(shí)候本身是不會(huì)用到緩沖區(qū)(內(nèi)存)的,是與文件本身直接操作的,,而字符流在操作的時(shí)候是使用到緩沖區(qū)的
字節(jié)流在操作文件時(shí),,即使不關(guān)閉資源(close方法),文件也能輸出,,但是如果字符流不使用close方法的話,,則不會(huì)輸出任何內(nèi)容,說明字符流用的是緩沖區(qū),,并且可以使用flush方法強(qiáng)制進(jìn)行刷新緩沖區(qū),,這時(shí)才能在不close的情況下輸出內(nèi)容
那開發(fā)中究竟用字節(jié)流好還是用字符流好呢?
在所有的硬盤上保存文件或進(jìn)行傳輸?shù)臅r(shí)候都是以字節(jié)的方法進(jìn)行的,,包括圖片也是按字節(jié)完成,,而字符是只有在內(nèi)存中才會(huì)形成的,所以使用字節(jié)的操作是最多的,。
如果要java程序?qū)崿F(xiàn)一個(gè)拷貝功能,,應(yīng)該選用字節(jié)流進(jìn)行操作(可能拷貝的是圖片),并且采用邊讀邊寫的方式(節(jié)省內(nèi)存),。
|