[面試要點]java io程式設計
java io 簡介
慣例先祭出一張圖
[1]輸入位元組流InputStream:InputStream 是所有的輸入位元組流的父類,它是一個抽象類;ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三種基本的介質流,它們分別從Byte 陣列、StringBuffer、和本地檔案中讀取資料;PipedInputStream 是從與其它執行緒共用的管道中讀取資料;ObjectInputStream 和所有FilterInputStream 的子類都是裝飾流(裝飾器模式的主角)。
[2]輸出位元組流OutputStream:OutputStream 是所有的輸出位元組流的父類,它是一個抽象類。
ByteArrayOutputStream、FileOutputStream 是兩種基本的介質流,它們分別向Byte 陣列、和本地檔案中寫入資料。PipedOutputStream 是向與其它執行緒共用的管道中寫入資料,ObjectOutputStream 和所有FilterOutputStream 的子類都是裝飾流。
[3]字元輸入流Reader:Reader 是所有的輸入字元流的父類,它是一個抽象類;CharReader、StringReader 是兩種基本的介質流,它們分別將Char 陣列、String中讀取資料;PipedReader 是從與其它執行緒共用的管道中讀取資料;BufferedReader 很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader 物件;FilterReader 是所有自定義具體裝飾流的父類,其子類PushbackReader 對Reader 物件進行裝飾,會增加一個行號;InputStreamReader 是一個連線位元組流和字元流的橋樑,它將位元組流轉變為字元流。FileReader 可以說是一個達到此功能、常用的工具類,在其原始碼中明顯使用了將FileInputStream 轉變為Reader 的方法。我們可以從這個類中得到一定的技巧。Reader 中各個類的用途和使用方法基本和InputStream 中的類使用一致。
[4]字元輸出流Writer:Writer 是所有的輸出字元流的父類,它是一個抽象類;CharArrayWriter、StringWriter 是兩種基本的介質流,它們分別向Char 陣列、String 中寫入資料。PipedWriter 是向與其它執行緒共用的管道中寫入資料,BufferedWriter 是一個裝飾器為Writer 提供緩衝功能;PrintWriter 和PrintStream 極其類似,功能和使用也非常相似;
簡述: IO流簡單來說就是Input和Output流,IO流主要是用來處理裝置之間的資料傳輸,Java對於資料的操作都是通過流實現,而java用於操作流的物件都在IO包中。使用流物件要丟擲IO異常,IO異常為checked異常
分類:
按操作資料分為:位元組流和字元流。 如:Reader和InpurStream,只要是以stream結尾的都是位元組流 按流向分:輸入流和輸出流。如:InputStream和OutputStream,輸入則為input或reader,輸出則為output或writer,應用中主要將外來的資料流(檔案來的,或者網路傳輸流等)首先通過輸入流輸入到記憶體,處理之後通過輸出流輸出 按功能分:節點流和過濾流 節點流: 用於直接操作目標裝置的流 過濾流: 是對一個已存在的流的連結和封裝,通過對資料進行處理為程式提供功能強大、靈活的讀寫功能。
可以把我們的程式想象成一個容器(記憶體),把要處理的資料流通過輸入流(input,reader)輸入,處理後,通過輸出流(output ,writer)輸出
字元流
- 字元流簡介
*字元流中的物件融合了編碼表,也就是系統預設的編碼表。我們的系統一般都是GBK編碼
- 字元流只用來處理文字資料
- 字元流在處理輸出流時必須flush(重新整理)才能將資料輸出
例項一:在硬碟建立一個檔案,寫入一些文字資訊
package com.oldbig.io;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//建立一個FileWriter物件,該物件一被初始化就必須要明確被操作的檔案。
//而且該檔案會被建立到指定目錄下。如果該目錄有同名檔案,那麼該檔案將被覆蓋。
//若在後面加入引數true,則不覆蓋檔案,在檔案後面新增文字,例如:FileWriter("D:\\ioTest\\1.txt",true);
FileWriter fw = new FileWriter("D:\\ioTest\\1.txt");
//呼叫write的方法將字串寫到流中
fw.write("hello word");
//重新整理流物件緩衝中的資料,將資料刷到目的地中
fw.flush();
//關閉流資源,但是關閉之前會重新整理一次內部緩衝中的資料。當我們結束輸入時候,必須close();
fw.write("test");
fw.close();
//flush和close的區別:flush重新整理後可以繼續輸入,close重新整理後不能繼續輸入。
}
}
例項二:使用FileReader對檔案進行讀取
private static void singleRead() throws IOException {
FileReader fr = null;
try{
//建立一個檔案讀取流物件,和指定名稱的檔案關聯。
//要保證檔案已經存在,否則會發生異常:FileNotFoundException
fr = new FileReader("D:\\ioTest\\1.txt");
//將檔案流包裝成緩衝流,讀取更方便,若直接用FileReader的read方法讀取的是int資料不是文字資料
BufferedReader br = new BufferedReader(fr);
String ch = null;
while((ch=br.readLine()) != null){
System.out.println(ch);
}
}catch(IOException e){
e.printStackTrace();
}finally{
fr.close();
}
}
例項:複製文字–>另一文字
private static void singleRead() throws IOException {
FileReader fr = null;
try{
//建立一個檔案讀取流物件,和指定名稱的檔案關聯。
//要保證檔案已經存在,否則會發生異常:FileNotFoundException
fr = new FileReader("D:\\ioTest\\1.txt");
//將檔案流包裝成緩衝流,讀取更方便
BufferedReader br = new BufferedReader(fr);
String ch = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\ioTest\\2.txt"));
while((ch=br.readLine()) != null){
System.out.println(ch);
bw.write(ch);
bw.newLine(); //換行
bw.flush(); //清空緩衝區
}
}catch(IOException e){
e.printStackTrace();
}finally{
fr.close();
}
}
剛剛用到緩衝區:字元流的緩衝區:BufferedReader和BufferedWriter
緩衝區的出現時為了提高流的操作效率而出現的.
需要被提高效率的流作為引數傳遞給緩衝區的建構函式
在緩衝區中封裝了一個數組,存入資料後一次取出
readline()只返回回車符前面的字元,不返回回車符。如果是複製的話,必須加入newLine(),寫入回車符
位元組流
簡述:
1、位元組流和字元流的基本操作是相同的,但是要想操作媒體流就需要用到位元組流。(媒體檔案也是以位元組儲存的)
2、讀寫位元組流:InputStream 輸入流(讀)和OutputStream 輸出流(寫)
3、位元組流操作可以不用重新整理流操作。
4、InputStream特有方法:
int available();//返回檔案中的位元組個數
例項:複製一張圖片
package com.oldbig.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyStream {
public static void main(String[] args) {
// TODO Auto-generated method stub
copyJpg();
System.out.println("複製完成");
}
private static void copyJpg() {
// TODO Auto-generated method stub
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fis = new FileInputStream("D://ioTest//1.jpg");
fos = new FileOutputStream("D://ioTest//2.jpg");
byte[] info = new byte[1024];
int len = 0;
while((len = fis.read(info)) != -1 ){
fos.write(info, 0, len);
}
}catch(IOException e){
e.printStackTrace();
throw new RuntimeException("複製檔案異常");
}finally{
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
流操作規律
System.out: 對應的標準輸出裝置:控制檯 //它是PrintStream物件,(PrintStream:列印流。OutputStream的子類)
System.in: 對應的標準輸入裝置:鍵盤 //它是InputStream物件
示例:從鍵盤錄入流,列印到控制檯上
package com.oldbig.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class SystemInOutDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedReader br = null;
BufferedWriter bw = null;
try{
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
//InputSteamReader:讀取位元組並將其解碼為字元
br = new BufferedReader(isr);
//OutputStreamWriter:要寫入流中的字元編碼成位元組
bw = new BufferedWriter(new OutputStreamWriter(System.out));
String info = null;
while((info = br.readLine()) != null){
bw.write(info);
bw.newLine();
bw.flush();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
java 管道通訊
Java提供管道功能,實現管道通訊的類有兩組:PipedInputStream和PipedOutputStream或者是PipedReader和PipedWriter。管道通訊主要用於不同執行緒間的通訊。
一個PipedInputStream例項物件必須和一個PipedOutputStream例項物件進行連線而產生一個通訊管道。PipedOutputStream向管道中寫入資料,PipedIntputStream讀取PipedOutputStream向管道中寫入的資料。一個執行緒的PipedInputStream物件能夠從另外一個執行緒的PipedOutputStream物件中讀取資料。
例項:兩個執行緒之間建立通訊管道
package com.oldbig.io;
import java.io.IOException;
import java.io.PipedOutputStream;
public class PipedSend extends Thread{
private PipedOutputStream out = new PipedOutputStream();
public PipedOutputStream getOut() {
return out;
}
public void run(){
String info = "hello ,receiver";
try{
out.write(info.getBytes()); //寫入資料
out.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
package com.oldbig.io;
import java.io.IOException;
import java.io.PipedInputStream;
public class PipedReader extends Thread{
private PipedInputStream in = new PipedInputStream();
public PipedInputStream getIn() {
return in;
}
@Override
public void run() {
// TODO Auto-generated method stub
byte[] info = new byte[1024];
try{
int len = in.read(info);
System.out.println("receive from send :" + new String(info,0,len));
in.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
public class PipedTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
PipedSend send = new PipedSend();
PipedReader reader = new PipedReader();
PipedOutputStream out = send.getOut();
PipedInputStream in = reader.getIn();
in.connect(out);//或者也可以用out.connect(in);
send.start();
reader.start();
}
}
總結
*位元組流和字元流的區別:
位元組流沒有緩衝區,是直接輸出的,而字元流是輸出到緩衝區的。因此在輸出時,而字元流只有在呼叫close()方法關閉緩衝區時,資訊才輸出。要想字元流在未關閉時輸出資訊,則需要手動呼叫flush()方法。
· 讀寫單位不同:位元組流以位元組(8bit)為單位,字元流以字元為單位,根據碼錶對映字元,一次可能讀多個位元組。
· 處理物件不同:位元組流能處理所有型別的資料(如圖片、avi等),而字元流只能處理字元型別的資料。
結論:只要是處理純文字資料,就優先考慮使用字元流。除此之外都使用位元組流
*什麼是java序列化,如何實現java序列化?
我們有時候將一個java物件變成位元組流的形式傳出去或者從一個位元組流中恢復成一個java物件,例如,要將java物件儲存到硬碟或者傳送給網路上的其他計算機,這個過程我們可以自己寫程式碼去把一個java物件變成某個格式的位元組流再傳輸,但是,jre本身就提供了這種支援,我們可以呼叫OutputStream的writeObject方法來做,如果要讓java 幫我們做,要被傳輸的物件必須實現serializable介面,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable介面,該介面是一個mini介面,其中沒有需要實現的方法,implements Serializable只是為了標註該物件是可被序列化的。
例如,在web開發中,如果物件被儲存在了Session中,tomcat在重啟時要把Session物件序列化到硬碟,這個物件就必須實現Serializable介面。如果物件要經過分散式系統進行網路傳輸或通過rmi等遠端呼叫,這就需要在網路上傳輸物件,被傳輸的物件就必須實現Serializable介面。