- 直接使用InputStream流接收System.in,使用最樸素的read(byte[] buf)方法,該方法每次讀入一行並存放到字符數組中,如ReadFromKeyBoard1.java所示
- 使用InputStreamReader將InputStream流封裝成字符流,然後使用字符流中的方法,如ReadFromKeyBoard2.java所示
- 使用BufferedReader將字符流封裝成緩衝輸入流,提高效率,如ReadFromKeyBoard3.java所示
/*
該示例直接使用InputStream流
*/
import java.io.*;
class ReadFromKeyBoard1
{
public static void main(String[] args) throws IOException
{
//InputStream儘管是抽象類,不可以new出對象,但可以接收一個對象的引用
InputStream is=System.in;
byte[] buf =new byte[1024];
int num;
while(true)
{
num=is.read(buf);
//之所以要減去2,是因爲Windows下的換行回車包含兩個字節
String str=new String(buf,0,num-2);
if(str.equals("over"))
break;
else
System.out.println(str);
}
is.close();
}
}
/*
該示例直接使用InputStreamReader流封裝原始的字節流,
使其成爲字符流,使用字符流的方法
*/
import java.io.*;
class ReadFromKeyBoard2
{
public static void main(String[] args) throws IOException
{
InputStreamReader isr= new InputStreamReader(System.in);
char[] buf =new char[1024];
int num;
while(true)
{
num=isr.read(buf);
String str=new String(buf,0,num-2);
if(str.equals("over"))
break;
else
System.out.println(str);
}
isr.close();
}
}
/*
該示例直接使用InputStreamReader流封裝原始的字節流,
再用BufferedReader流封裝,最後使用BufferedReader的方法
尤其是readLine()方法
*/
import java.io.*;
class ReadFromKeyBoard3
{
public static void main(String[] args) throws IOException
{
//該方法常是獲取鍵盤輸入的最常用方法
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
String str=null;
while(true)
{
str=br.readLine();
if(str.equals("over"))
break;
else
System.out.println(str);
}
br.close();
}
}
- 直接使用字符輸入流FileReader從磁盤文件中讀取數據,並且逐個讀取字符、逐個打印字符,如ReadFromFile1.java所示
- 直接使用字符輸入流FileReader從磁盤文件中讀取數據,讀取出所有字符到一個數組中再打印,如ReadFromFile2.java所示
- 使用BufferedReader封裝FileReader流,以提升性能,如ReadFromFile3.java所示
- 直接使用字節輸入流FileInputStream從文件中讀取數據,此處也可以對字節輸入流再封裝成字符流,衍生出另外三種方法(如小節1中所示)。。。篇幅限制,我們只演示最樸素的一種,如ReadFromFile4.java所示
- 對System.in重定向到磁盤文件,如ReadFromFile5.java所示
/*
直接按字符流從C盤的ruirui.txt文件中讀取數據,
然後打印到控制檯上
*/
import java.io.*;
class ReadFromFile1
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("C:\\ruirui.txt");
int num;
while((num=fr.read())!=-1)
{
if(num=='\n')
continue;
else if(num=='\r')
System.out.println();//讀入換行符就換行
else
{
System.out.print((char)num);
}
}
fr.close();
}
}
/*
按字符流從C盤的ruirui.txt文件中讀取數據,
然後打印到控制檯上.
和ReadFromFile1不同的是其採用read(char[])的方法
*/
import java.io.*;
class ReadFromFile2
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("C:\\ruirui.txt");
char[] buf= new char[1024];
int num;//記錄讀取的字符個數
num=fr.read(buf);//讀取所有的字符
System.out.print(new String(buf,0,num));
fr.close();
}
}
/*
按字符流從C盤的ruirui.txt文件中讀取數據,
然後打印到控制檯上,並使用BufferedReader以將提高性能
使用BufferedReader中的readLine()方法
*/
import java.io.*;
class ReadFromFile3
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("C:\\ruirui.txt");
BufferedReader br =new BufferedReader(fr);
String str;
while((str=br.readLine())!=null)
{
System.out.println(str);
}
fr.close();
}
}
/*
按字節流從C盤的ruirui.txt文件中讀取數據,
然後打印到控制檯上
和字節流不同的是,只能有一種方法(ReadFromFile1和
ReadFromFile2是字符流的兩種方法)。。。因爲只讀取
一個字節將無法打印字符。。
當然也有一種補救的方法,讀取兩個字節後再打印,
不過過於複雜。。。。
同理,這裏如果將字節流封裝成字符流,或將字符流再封裝成緩衝區
又可以演變出兩種方法。。爲節省篇幅,此處省略。。。
*/
import java.io.*;
class ReadFromFile4
{
public static void main(String[] args) throws IOException
{
FileInputStream fis=new FileInputStream("C:\\ruirui.txt");
byte[] buf=new byte[1024];
int num;
num=fis.read(buf);
System.out.print(new String(buf,0,num));
}
}
/*
考慮:
對System.in流進行重新設置,使其指向磁盤文件。。。
此處又可以延伸出三個方法,
爲節省篇幅,此處只演示一個方法
*/
import java.io.*;
class ReadFromFile5
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("C:\\ruirui.txt"));
BufferedReader bd=new BufferedReader(new InputStreamReader(System.in));
String str;
while(true)
{
str=bd.readLine();
if(str==null)
break;
System.out.println(str);
}
bd.close();
}
}
- 直接使用字節輸出流OutputStream接收對象,如WriteToScreen1.java所示
- 將字節輸出流OutputStream封裝成字符輸出流OutputStreamWriter,如WriteToScreen2.java所示
- 將字符輸出流OutputStreamWriter封裝成緩衝字符流BufferedWriter,如WriteToScreen3.java所示
- 使用PrintStream接收對象,然後使用Print方法,如WriteToScreen4.java所示
/*
要向控制檯輸出,必須對System.out進行操作。。
但是System.out也是字節流,一般而言只能直接
使用字節流所擁有的方法。。但其又是特殊的字節流
對象(PrintStream類的對象),所以可以具備一些
特殊的方法,
WriteToScreen1演示的是使用最基本的字節輸出流
OutputStream中的方法,將C:\\ruirui.txt中的字符
打印到控制檯上
*/
import java.io.*;
class WriteToScreen1
{
public static void main(String[] args) throws IOException
{
OutputStream os=System.out;
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
while(true)
{
str=br.readLine();
if(str==null)
break;
str=str+"\n\r"; //打印換行符
os.write(str.getBytes());//和WriteToScreen2的唯一不同,Write方法中需要
//轉爲字節數組
os.flush();
}
os.close();
br.close();
}
}
/*
同樣地,我們可以講字節流對象System.out封裝成
字符流對象從而使用字符流對象中的方法
*/
import java.io.*;
class WriteToScreen2
{
public static void main(String[] args) throws IOException
{
OutputStream os=System.out;
OutputStreamWriter osw=new OutputStreamWriter(os);
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
while(true)
{
str=br.readLine();
if(str==null)
break;
osw.write(str+"\n\r");
osw.flush(); //千萬不可忘記刷新
}
os.close();
osw.close();
br.close();
}
}
/*
爲使得“換行符”的打印能夠跨平臺,我們考慮
使用BufferedWriter中的newLine()方法,
爲此必須先將字節流對象封裝成字符流對象,
再用BufferedReader封裝起來
*/
import java.io.*;
class WriteToScreen3
{
public static void main(String[] args) throws IOException
{
OutputStream os=System.out;
OutputStreamWriter osw=new OutputStreamWriter(os);
BufferedWriter bw=new BufferedWriter(osw);
//這裏其實可以一步到位:
//BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
while(true)
{
str=br.readLine();
if(str==null)
break;
bw.write(str);
bw.newLine(); //該換行方法可以跨平臺
bw.flush(); //不要忘記刷新
}
os.close();
osw.close();
bw.close();
br.close();
}
}
/*
我們發現System.out不只是OutputStream類的對象,
其更是子類PrintStream的對象。。。
PrintStream是一種特殊的流,其爲字節流,卻擁有
許多實用的方法(甚至比字符流還要多),比如說
println方法。。。
*/
import java.io.*;
class WriteToScreen4
{
public static void main(String[] args) throws IOException
{
PrintStream ps=System.out;
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
while(true)
{
str=br.readLine();
if(str==null)
break;
ps.println(str);//此處相當於直接調用System.out.println(str)
}
ps.close();
br.close();
}
}
4)向磁盤文件中輸出
可以採取字符流或者字節流向磁盤文件中進行輸出操作,其中字節流又可以封裝成字符流,而且可以將System.out重定向到磁盤文件。。。所以有以下幾種方式:
- 直接採用字符輸出流FileWriter,如WriteToFile1.java所示
- 帶有緩衝區的字符輸出流BufferedWriter,如WriteToFile2.java所示
- 直接採用字節輸出流FileOutputStream,如WriteToFile3.java所示
- 將System.out重定向到磁盤文件,並採用OutputStream接收,使用最樸素的OutputStream中的Write方法,如WriteToFile4.java所示
- 將System.out重定向到磁盤文件,並採用PrintStream接收,使用PrinStream中高級的Print或println方法,如WriteToFile5.java所示
/*
我們仍然採用緩衝區字符流的方式從C:\\ruirui.txt中讀取數據
存儲到C:\\haoxiaoya.txt中。。
同讀取類似,存儲到磁盤文件可以用字符流也可以用字節流,其中字節流
可以封裝成字符流,或者對System.out進行重新的定義
*/
import java.io.*;
class WriteToFile1 //採用字符流的直接寫入
{
public static void main(String[] args) throws IOException
{
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
FileWriter fw=new FileWriter("C:\\haoxiaoya.txt",true);
while(true)
{
str=br.readLine();
if(str==null)
break;
fw.write(str+"\r\n");
}
fw.close();
br.close();
}
}
/*
採用字符流直接寫入,但是封裝成緩衝區對象
從而使用可以跨平臺的“換行符”。。。
需要注意的是,由於BufferedReader的readLine()方法
在讀入數據時會忽略行末的“換行符”,所以在寫入的時候
需要重新添加。。。
而FileReader的read(char[] buf)方法會將換行符也讀取
出來,從而不需要添加新的換行符。。。該示例在
WriteToFile3中使用。。。
*/
import java.io.*;
class WriteToFile2 //採用字符流的直接寫入,並封裝成緩衝區對象
{
public static void main(String[] args) throws IOException
{
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
FileWriter fw=new FileWriter("C:\\haoxiaoya.txt",true);
//這裏的true表示在原來的文件末尾添加
BufferedWriter bw=new BufferedWriter(fw);
while(true)
{
str=br.readLine();
if(str==null)
break;
bw.write(str);
bw.newLine();
bw.flush();
}
fw.close();//需要提醒的是,在緩衝字節流(BufferedWriter或BufferReader)關閉之前,
//若還未進行刷新操作(如本例中的bw.flush()),不可直接關閉緩衝字節流中封裝的流對象
//也就是說,若註釋掉bw.flush(),程序是會報錯的,因爲那樣的flush操作會等到不可以
//bw.close()關閉時進行,在此之前關閉所封裝的流對象(如本例中的fw對象)
//但如果將bw.flush()和fw.close()同時註釋掉,那麼bw的刷新和fw的關閉都將由
//bw在close中自動進行,將不會產生差錯
bw.close();
br.close();
}
}
/*
需要注意的是,由於BufferedReader的readLine()方法
在讀入數據時會忽略行末的“換行符”,所以在寫入的時候
需要重新添加。。。
而FileReader的read(char[] buf)方法會將換行符也讀取
出來,從而不需要添加新的換行符。。。該示例在
WriteToFile3中使用。。。
在WriteToFile3中我們使用FileReader流對象中的
read(char[] buf)的方法讀取文件,然後通過字節流
直接寫入到C:\\haoxiaoya.txt中
此處在寫入時,也可以將字節流封裝成字符流,並且可以
封裝成字符流緩衝區。。。。可以衍生出兩種新的方法,
但此處爲節省篇幅,略去
*/
import java.io.*;
class WriteToFile3 //採用字節流的直接寫入
{
public static void main(String[] args) throws IOException
{
// BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
// String str=null;
// 此處使用FileReader字符流,而不採用緩衝區
FileReader fr=new FileReader("C:\\ruirui.txt");
char[] buf=new char[1024];
int num=0;
FileOutputStream os=new FileOutputStream("C:\\haoxiaoya.txt");
num=fr.read(buf);
os.write(new String(buf).getBytes(),0,num);
//因爲FileReader讀出的是字符數組,而FileOutputStream只接受字節數組
//所以需要做轉換
//不用寫入換行符,因爲FileReader的read(char[] buf)將會讀取源文件中的換行符
os.close();
fr.close();
}
}
/*
仍然使用字符流FileReader的read(char[] buf)方法讀入
但在寫出時,我們採用對System.out進行重定向
在對System.out這個字節流對象進行重定向時,
也可以將其再包裝爲字符流對象,以及字符流緩衝區對象。
衍生出另外兩種方法,爲節省篇幅,省去。。
甚至可以採用System.out的print方法。。。
如WriteToFile5所示
*/
import java.io.*;
class WriteToFile4 //採用System.out進行重定向
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("C:\\ruirui.txt");
char[] buf=new char[1024];
int num=0;
System.setOut(new PrintStream("C:\\haoxiaoya.txt"));
OutputStream fos=System.out;
num=fr.read(buf);
fos.write(new String(buf).getBytes(),0,num);
//因爲FileReader讀出的是字符數組,而OutputStream只接受字節數組
//所以需要做轉換
//不用寫入換行符,因爲FileReader的read(char[] buf)將會讀取源文件中的換行符
fos.close();
fr.close();
}
}
/*
仍然使用字符流FileReader的read(char[] buf)方法讀入
但在寫出時,我們採用對System.out進行重定向
甚至可以採用System.out的print方法。。。
如WriteToFile5所示
*/
import java.io.*;
class WriteToFile5 //採用System.out進行重定向
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("C:\\ruirui.txt");
char[] buf=new char[1024];
int num=0;
System.setOut(new PrintStream("C:\\haoxiaoya.txt"));
//使用PrintStream接收對象
PrintStream ps=System.out;
num=fr.read(buf);
//使用PrintStream的print方法
ps.print(new String(buf,0,num));
ps.close();
fr.close();
}
}
5)演示一種從鍵盤中輸入字符串,然後直接在控制檯上打印的示例。。。當輸入“over”字符串時,程序結束,如ZhuHangPrint.java所示
/*
本示例演示從鍵盤輸入,並逐行打印。。
當鍵盤輸入“over”字符串時,程序停止
*/
import java.io.*;
class ZhuHangPrint
{
public static void main(String[] args) throws IOException
{
//使用最常用的鍵盤輸入:BufferedReader流
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str;
while(true)
{
str=br.readLine();
if(str.equals("over"))
break;
System.out.println(str);//此處要用“換行打印”println是因爲BufferedReader
//的readLine()方法不讀取源中的換行符
}
br.close();
}
}
三、流操作中的小感悟
1.採用BufferedWriter或BufferedReader封裝字符流對象時,緩衝流對象的刷新必須在其內部封裝的字符流關閉之前。。。如下面的代碼就會報錯
FileWriter fw=new FileWriter("C:\\haoxiaoya.txt");
BufferedWriter bw=new BufferedWriter(fw);
bw.write(“ruirui”);
bw.newLine();
// bw.flush();
fw.close();
bw.close();
代碼中bw對象的刷新只能等待被close時進行,在此之前若關閉其封裝的fw對象,就會出錯。。。但若將fw.close()註釋掉,代碼就會正常執行,因爲那樣的bw.flush();和fw.close();都會在bw.close();中自動執行,系統的內部機制保證了其運行順序的正確性。。這也是WriteToFile2.java中提及的。
2.BufferedReader()流對象中的readLine()方法,將不讀取源文件中的換行符,因此當在輸出時需要換行時,需要手動添加“換行”。。。
而FileReader()中的read(char[] buf)將會讀取源文件中的換行符,因此在輸出時不用添加新的“換行”。。。這也是WriteToFile4.java中提及的。
3.儘管在流的關閉close操作中會自動進行刷新flush操作,但是我們儘量還是要顯示進行flush操作,以避免一些麻煩,如下面的代碼WriteToScreenDemo.java會沒有輸出現象。。
/*
同樣地,我們可以講字節流對象System.out封裝成
字符流對象從而使用字符流對象中的方法
*/
import java.io.*;
class WriteToScreenDemo
{
public static void main(String[] args) throws IOException
{
OutputStream os=System.out;
OutputStreamWriter osw=new OutputStreamWriter(os);
BufferedReader br =new BufferedReader(new FileReader("C:\\ruirui.txt"));
String str=null;
while(true)
{
str=br.readLine();
if(str==null)
break;
osw.write(str+"\n\r");
// osw.flush(); //千萬不可忘記刷新
}
os.close();
osw.close();
br.close();
}
}
這是因爲在osw隱式地刷新之前,已經將其封裝的os對象關閉了,所以會沒有輸出現象。。。。這一點和第一點有點類似,所不同的是,第一點中涉及緩衝流BufferedWriter和BufferedReader,錯誤的操作順序會直接報錯;而這一點中錯誤的操作順序只是會產生錯誤的結果(如沒有輸出現象)。這也是WriteToScreen2.java中提及的