1. 程式人生 > >[面試要點]java io程式設計

[面試要點]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)輸出

字元流

  1. 字元流簡介
    *字元流中的物件融合了編碼表,也就是系統預設的編碼表。我們的系統一般都是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介面。