上篇文章Java 位元組流操作介紹了java中基本的位元組流操作,但是我們常常對于字元操作,如果使用位元組流來實作輸入輸出就顯得麻煩,我們可以使用字元流來實作對我們看得見的字元char進行操作,主要内容如下:
基本流(Reader/Writer)
轉換流(InputStreamReader/OutputStreamEWriter)
檔案字元流(FileReader/FileWriter)
字元數組流(charArrayReader/charArrayWriter)
緩沖字元流(BufferedReader/BufferedWriter)
裝飾類(PrintWriter)
一、基本流
位元組流的基本流是InputStream/OutputStream,這裡的字元流的基本流是Reader/Writer,他們都是抽象類,想要實作更加複雜的操作就必須要子類來擴充。他們内部主要的就是read和write方法,實作單個字元及字元數組的讀取的寫入。此處就不再列出,我們将會從他們的子類中看看這些方法的實作。
二、轉換流
InputStreamReader和OutputStreamWriter這兩個類型流,在整個字元流中是十分重要的流,他們實作了和位元組流的轉換。先看看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 類型的常量(這是一個十分重要的成員),一堆構造方法通過不同的方式指定了外部傳入的InputStream類型的參數和解碼類型。我們看到,read方法中調用的是上述的sd常量(這是一個StreamDecoder類型的常量)的方法。這個StreamDecoder類實際上完成了将位元組轉換成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數組,還可以寫字元串(實際上還是調用了getchars方法擷取該字元串的内置char數組,然後調用寫數組的方法)。
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兩個流,繼承的是上述的兩個轉換流。内部的方法非常簡單,隻是幾個構造方法而已。
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));
}
從源代碼中可以看出來,這兩個檔案流完全依賴父類。自己基本沒有擴充父類,使用的方法都是父類的。你可以通過傳檔案的路徑或者建構File類作為構造參數傳入。
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);
}
}
一樣可以達到讀取字元的效果,實際上上述代碼可以轉換為:
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的内部還是通過super調用父類的構造方法
四、字元數組流
和之前介紹的位元組數組流類似,都是為了能提高效率防止記憶體浪費而設計的。看看我們上面的一段代碼:
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,那如果檔案足夠大,我們勢必要建立更大的字元數組(這是一種浪費記憶體)。我們可以使用字元數組流來實作動态擴容,解決記憶體空間。上述代碼可以改寫:
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();
}
}
這樣,即使檔案再大,我們也不會浪費很多記憶體空間。至于StingReader和StringWriter兩個流其實是類似的,因為String的本質是char數組, 是以他們必然也是有數組作為最基本的操作。
五、緩沖字元流
字元的緩沖流和位元組的緩沖流是類似的。都是裝飾流。
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的流,他是一個非常友善的類,可以直接指定檔案名作為參數,可以指定編碼類型,還支援自動緩沖技術,可以自動轉換多種基本類型為字元串形式寫入檔案中。在我們日常使用寫入檔案時,可以優先考慮使用該類。
protected Writer out;
private final boolean autoFlush;
//構造方法
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寫入到檔案中,非常的簡單友善,可以指定檔案路徑,File,OutputStream作為構造方法的形參。這一切的轉換都封裝了,自動提供緩沖流。這是一種比較好的輸出流,在之後的使用中,如果遇到輸出到檔案,應該優先考慮PrintWriter。
标簽:Java,位元組,void,throws,char,new,操作,public,String
來源: https://www.cnblogs.com/Bkxk/p/11731792.html