?????上篇文章Java 字節(jié)流操作介紹了java中基本的字節(jié)流操作俐镐,但是我們常常對于字符操作,如果使用字節(jié)流來實現(xiàn)輸入輸出就顯得麻煩碘梢,我們可以使用字符流來實現(xiàn)對我們看得見的字符char進行操作蜈块,主要內(nèi)容如下:
- 基本流(Reader/Writer)
- 轉(zhuǎn)換流(InputStreamReader/OutputStreamEWriter)
- 文件字符流(FileReader/FileWriter)
- 字符數(shù)組流(charArrayReader/charArrayWriter)
- 緩沖字符流(BufferedReader/BufferedWriter)
- 裝飾類(PrintWriter)
一、基本流
?????字節(jié)流的基本流是InputStream/OutputStream这嚣,這里的字符流的基本流是Reader/Writer,他們都是抽象類塞俱,想要實現(xiàn)更加復(fù)雜的操作就必須要子類來擴充姐帚。他們內(nèi)部主要的就是read和write方法,實現(xiàn)單個字符及字符數(shù)組的讀取的寫入障涯。此處就不再列出罐旗,我們將會從他們的子類中看看這些方法的實現(xiàn)。
二唯蝶、轉(zhuǎn)換流
?????InputStreamReader和OutputStreamWriter這兩個類型流九秀,在整個字符流中是十分重要的流,他們實現(xiàn)了和字節(jié)流的轉(zhuǎn)換粘我。先看看InputStreamReader:
private final StreamDecoder sd;
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in, String charsetName)
public InputStreamReader(InputStream in, Charset cs)
public InputStreamReader(InputStream in, CharsetDecoder dec)
public int read() throws IOException {
return sd.read();
}
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
?????首先定義了一個StreamDecoder 類型的常量(這是一個十分重要的成員)鼓蜒,一堆構(gòu)造方法通過不同的方式指定了外部傳入的InputStream類型的參數(shù)和解碼類型。我們看到,read方法中調(diào)用的是上述的sd常量(這是一個StreamDecoder類型的常量)的方法都弹。這個StreamDecoder類實際上完成了將字節(jié)轉(zhuǎn)換成char的操作娇豫。
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
InputStreamReader inr = new InputStreamReader(new FileInputStream("hello.txt"));
char[] chs = new char[100];
inr.read(chs);
System.out.println(chs);
inr.close();
}
}
?????上述代碼展示了如何從文件中按照指定的解碼方式讀取出字符,OutputStreamWriter幾乎是逆操作:
public void write(int c)
public void write(char cbuf[], int off, int len)
public void write(String str, int off, int len)
?????可以寫int畅厢,可以寫char數(shù)組锤躁,還可以寫字符串(實際上還是調(diào)用了getchars方法獲取該字符串的內(nèi)置char數(shù)組,然后調(diào)用寫數(shù)組的方法)或详。
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
OutputStreamWriter ow = new OutputStreamWriter(new FileOutputStream("hello.txt"));
ow.write("walker");
ow.close();
}
}
/*可以明顯感知,對字符操作的簡單直接*/
三郭计、文件字符流
????? FileReader和FileWriter兩個流霸琴,繼承的是上述的兩個轉(zhuǎn)換流。內(nèi)部的方法非常簡單昭伸,只是幾個構(gòu)造方法而已梧乘。
public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
?????從源代碼中可以看出來,這兩個文件流完全依賴父類庐杨。自己基本沒有擴展父類选调,使用的方法都是父類的。你可以通過傳文件的路徑或者構(gòu)建File類作為構(gòu)造參數(shù)傳入灵份。
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("hello.txt");
char[] chars = new char[1024];
fr.read(chars);
System.out.println(chars);
}
}
?????一樣可以達到讀取字符的效果仁堪,實際上上述代碼可以轉(zhuǎn)換為:
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
InputStreamReader ins = new InputStreamReader(new FileInputStream("hello.txt"));
char[] chars = new char[1024];
ins.read(chars);
System.out.println(chars);
}
}
//因為FIleReader的內(nèi)部還是通過super調(diào)用父類的構(gòu)造方法
四、字符數(shù)組流
?????和之前介紹的字節(jié)數(shù)組流類似填渠,都是為了能提高效率防止內(nèi)存浪費而設(shè)計的弦聂。看看我們上面的一段代碼:
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("hello.txt");
char[] chars = new char[1024];
fr.read(chars);
System.out.println(chars);
}
}
?????這段程序其實是不完善的氛什,因為我們默認hello文件中的字符容量小于等于1024莺葫,那如果文件足夠大,我們勢必要創(chuàng)建更大的字符數(shù)組(這是一種浪費內(nèi)存)枪眉。我們可以使用字符數(shù)組流來實現(xiàn)動態(tài)擴容捺檬,解決內(nèi)存空間。上述代碼可以改寫:
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("hello.txt");
int x = 0;
CharArrayWriter chw = new CharArrayWriter();
while ((x = fr.read()) != -1){
chw.write(x);
}
System.out.println(chw.toString());
chw.close();
}
}
?????這樣贸铜,即使文件再大堡纬,我們也不會浪費很多內(nèi)存空間。至于StingReader和StringWriter兩個流其實是類似的萨脑,因為String的本質(zhì)是char數(shù)組隐轩, 所以他們必然也是有數(shù)組作為最基本的操作。
五渤早、緩沖字符流
?????字符的緩沖流和字節(jié)的緩沖流是類似的职车。都是裝飾流。
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
BufferedReader bins = new BufferedReader(new FileReader("hello.txt"));
BufferedWriter bws = new BufferedWriter(new FileWriter("hello.txt",true));
int x;
while ((x = bins.read()) != -1){
System.out.println((char)x);
bws.write(x);
}
}
}
//緩沖讀和緩沖寫
六、PrintWriter
?????這是一個繼承與Writer的流悴灵,他是一個非常方便的類扛芽,可以直接指定文件名作為參數(shù),可以指定編碼類型积瞒,還支持自動緩沖技術(shù)川尖,可以自動轉(zhuǎn)換多種基本類型為字符串形式寫入文件中。在我們?nèi)粘J褂脤懭胛募r茫孔,可以優(yōu)先考慮使用該類叮喳。
protected Writer out;
private final boolean autoFlush;
//構(gòu)造方法
public PrintWriter (Writer out) {
this(out, false);
}
public PrintWriter(OutputStream out) {
this(out, false);
}
public PrintWriter(String fileName) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
false);
public PrintWriter(File file) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
false);
}
//寫入一個character
public void write(int c) {
try {
synchronized (lock) {
ensureOpen();
out.write(c);
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
//寫入一個字符串
public void write(String s) {
write(s, 0, s.length());
}
//重載print方法
public void print(boolean b) {
write(b ? "true" : "false");
}
public void print(char c) {
write(c);
}
public void print(int i) {
write(String.valueOf(i));
}
public void println() {
newLine();
}
public void println(int x) {
synchronized (lock) {
print(x);
println();
}
}
public void println(String x) {
synchronized (lock) {
print(x);
println();
}
}
?????上述代碼中的print和println并非和我們的標準輸出流(System.out.println)同義,這里的print表示寫入到文件中缰贝。
public class Test_InputOrOutput {
public static void main(String[] args) throws IOException{
PrintWriter pw = new PrintWriter("hello.txt");
pw.println('x');
pw.close();
}
}
?????使用了PrintWriter寫入到文件中馍悟,非常的簡單方便,可以指定文件路徑剩晴,F(xiàn)ile锣咒,OutputStream作為構(gòu)造方法的形參。這一切的轉(zhuǎn)換都封裝了赞弥,自動提供緩沖流毅整。這是一種比較好的輸出流,在之后的使用中绽左,如果遇到輸出到文件悼嫉,應(yīng)該優(yōu)先考慮PrintWriter。
?????本篇文章結(jié)束了拼窥,這兩篇文章是我閱讀書籍和博客承粤,加上jdk源代碼總結(jié)得來,如有錯誤闯团,望大家指出辛臊!