1. 程式人生 > >6.5(java學習筆記)其他流(位元組陣列流,資料流,物件流,列印流)

6.5(java學習筆記)其他流(位元組陣列流,資料流,物件流,列印流)

一、位元組陣列流

  之前使用輸入輸出流的操作的物件是檔案,而這裡位元組陣列流操作的物件是記憶體,記憶體可以看做是一個位元組陣列。

  使用位元組陣列流讀寫就可以看做是從記憶體A到記憶體B的讀寫,物件時記憶體即位元組陣列。

  

  1.1構造方法

    ByteArrayOutputStream()//建立一個字元陣列輸出流

    ByteArrayInputStream(byte[] buf)//建立一個位元組陣列輸入流,這裡面的buff可看做記憶體物件即字元陣列

  

  2.2主要方法

    ByteArrayInputStream:

    read(byte[] bu)//讀取輸入流中的資料,放入bu中。

 

    ByteArrayOutputStream:

    public void write(byte[] bu)//將bu(可看做記憶體物件資料),寫入輸出流。

    byte[] toByteArray()//建立一個新的位元組陣列,並將輸出流中資料放入其中

 

  2.3例子

    

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream; public class ByteArrayStream { public static void main(String[] args) { // TODO Auto-generated method stub read(write()); } public static void read(byte[] by){ int len = 0; //將記憶體物件B放入輸入流 InputStream r = new BufferedInputStream(new
ByteArrayInputStream(by));//把這裡的by看做記憶體物件 byte[] flush = new byte[1024];//把flush看做另外一個記憶體物件 try { //將記憶體物件B與輸入流關聯,來後通過輸入流讀取物件B資料放入flush中 while(-1 != (len = r.read(flush))){//讀取輸入流中的資料放入flush,即讀取記憶體物件B中的資料 System.out.println(new String(flush,0,len));//打印出讀取的資料 } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static byte[] write(){ byte[] by = null;//記憶體物件B byte []info = "位元組陣列流".getBytes();//記憶體物件A ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { bos.write(info);//將記憶體A塊內容寫入輸出流 by = bos.toByteArray();//記憶體物件B接收輸出流中的資料 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return by;//返回記憶體物件B } }
執行結果:
位元組陣列流

 

wtire:首先將記憶體A的資料寫入輸出流,然後記憶體B獲取輸入流中的資料,最後將記憶體B作為返回值。

read:將記憶體B放入輸入流,然後通過輸入流讀取記憶體B中的資料放入flush中,然後將flush轉為字元打印出來。

這裡在一個程式中執行看著有點奇怪而且不好理解,我們就把記憶體A記憶體B看著是兩臺電腦各自記憶體,這樣便於理解一些。

 

二、資料流

  採用資料流進行讀寫可以允許將原始java資料型別寫入流中,即既保持了資料也儲存了資料型別。

  2.1構造方法

    DataInputStream(InputStream  in)

    DataOutputStream(OutStream out)

 

  2.2主要方法

    void writeInt(int v)//寫入int型資料

    void writeLong(long v)//寫入long型資料

    void writeUTF(String str)//將字串以UTF-8格式寫入輸出流

    

    int readInt()//讀取Int型資料並返回

    long readLong()//讀取long型資料並返回

    String readUTF()//讀取UTF-8轉換的字串

    基本操作方法與檔案讀寫無太大差別,只是加上了資料型別,這些方法時DataStream獨有的方法,故呼叫它們要避免多型。

 

  2.3例子

    

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class DateStream {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        write();
        read();
    }
    public static void read() throws IOException{
        DataInputStream dis = new DataInputStream(//資料流
                                    new BufferedInputStream(//緩衝流
                                            new FileInputStream(
                                                    new File("F:\\依風\\Desktop\\data.txt")
                                                    )
                                            )
                                    );
        //注意:這裡讀取型別的順序要和寫入時的型別順序對應,不然會出現錯誤。
        long lo = dis.readLong();//將不同型別用對應方法讀出。
        int in = dis.readInt();
        String str = dis.readUTF();
        dis.close();
        System.out.println(lo + "-->" + in +"-->" + str);
    }
    
    public static void write() throws IOException{
        long lo = 100L;
        int in = 21;
        String str = "DataStream";
        DataOutputStream dos = new DataOutputStream(//資料流
                                     new BufferedOutputStream(//緩衝流
                                         new FileOutputStream(
                                             new File("F:\\依風\\Desktop\\data.txt")
                                         )
                                     )
                               );
        dos.writeLong(lo);//將不同型別用對應的方法寫入
        dos.writeInt(in);
        dos.writeUTF(str);
        dos.flush();
        dos.close();
    }
}
執行結果:
100-->21-->DataStream

這裡一開始往檔案中寫入的是long型,然後是int型別最後是String

那麼讀取時也應該先讀long,然後int最後String。

如果寫入和讀取的順序不一致可能會導致讀取的資料有誤,也可以出現EOFException。

 

這裡寫入的資料不是給人類看的,而是給機器識別的。我可以開啟寫入的檔案會發現裡面會有亂碼。

 

 

三、物件流

    使用物件流,可以寫入、讀出物件的資訊以及屬性屬性。物件流和之前輸入輸出流功能類似,

    不過是將之前的檔案換成了物件,這裡的物件時我們通過new建立的物件。

 

    將物件寫如檔案實質是是將物件轉換為位元組序列,然後將位元組序列寫入檔案,這個稱為序列化。

    讀取位元組序列然後轉換為物件就稱為反序列化。

    物件被序列化必須實現java.io.Serializable介面,改介面表示可以序列化。物件的類沒有實現這個介面會出現一次次。

    物件中某些屬性不想被序列化可以加transient修飾,transient修飾就代表這個屬性不參加序列化。

 

    3.1構造方法

    Public ObjectOutputStream(OutputStream out)

    Public ObjectInputStream(InputStream in)

    

    3.2主要方法

     Object readObject()//從輸入流中讀取物件

     void writeObject(Object obj)//將obj寫入輸出流

 

    3.3例子 

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectStream {
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException{
        read(write());
    }
    //將物件寫入指定檔案,並返回指定檔案路徑資訊
    public static String write() throws FileNotFoundException, IOException{
        String filePath = "F:\\依風\\Desktop\\ObjectStream.txt";
        ObjectOutputStream oos = new ObjectOutputStream(//使用獨有方法,不發生多型
                                    new BufferedOutputStream(
                                        new FileOutputStream(
                                            new File(filePath))));
        oos.writeObject(new Employ("hcf",4000));//傳入物件
        oos.flush();
        oos.close();
        return filePath;
    }
    
    //接受指定檔案路徑資訊,並讀取檔案中的物件
    public static void read(String filePath) throws FileNotFoundException, IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(
                                    new BufferedInputStream(
                                        new FileInputStream(
                                            new File(filePath))));
        Employ em = (Employ)ois.readObject();//將讀取的物件強制轉型
        System.out.println(em.getName() + ":" + em.getMoney());//輸出物件資訊
    }
}


class Employ implements java.io.Serializable{//必須實現介面
    private transient String name;//姓名沒有被序列化
    private int money;
    public Employ(){}
    public Employ(String name,int money){
        setName(name);
        setMoney(money);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getMoney() {
        return money;
    }
    public void setMoney(int money) {
        this.money = money;
    }
}
執行結果:
null:4000

我們可以看到沒有被序列化的屬性顯示為null

比如一個矩形類中有長、寬屬性,還有面積屬性,

那麼序列化時可以不序列化面積屬性,因為面積屬性可以通過長寬計算出來。  

 

四、列印流

    列印流(PraintStream)類似輸出流,但列印流使用方便而且可以打印出任何型別的資料。

    想我們平常使用很多的System.out.println()就是呼叫列印流中的println()方法。

 

    4.1建構函式

    PrintStream(OutputStream out)//建立列印流

    PrintStream(OutputStream out, boolean autoFlush)//建立列印流,autoFlush為true代表自動重新整理緩衝區
    PrintStream(File fileName, String csn)//建立指定檔案的列印流,csn為編碼方式

 

    4.3主要方法

    print(......);//列印引數內容,幾乎可為任何形式引數,末尾不加回車。

    println(......)//列印引數內容,末尾加回車。

    

    

    4.4例子 

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;

public class Print {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException{
        PrintStream ps = new PrintStream(//常規初始化
                new BufferedOutputStream(
                    new FileOutputStream(
                        new File("F:\\依風\\Desktop\\print.txt"))));
        PrintStream pc = new PrintStream("F:\\依風\\Desktop\\printCsn.txt","GBK");//指定編碼
        PrintStream pf = new PrintStream(//自動重新整理
                new BufferedOutputStream(
                    new FileOutputStream(
                        new File("F:\\依風\\Desktop\\printFlush.txt"))),true);
        pf.println("autoFlush");
        pf.close();
        pc.print("GBK");
        pc.flush();
        pc.close();
        ps.print("print\n"+1.3);
        ps.flush();
        ps.close();
    }
}

執行結果:

 

4.5 Sytem.out和 System.in

我們平常呼叫System.out.println()函式列印,列印的內容是顯示在控制檯上的,System.out也是一個列印流。

而這個列印流關聯的就是控制檯,可以把控制檯也看做一個檔案,平常打印出來的資料就是往控制檯這個檔案列印。

那麼我們能否將這個檔案換成別的檔案呢,即呼叫System.out.println()不是向控制檯輸出資訊,而是向我們指定的檔案輸入資訊。

答案是可以的,System裡面提供了一個方法System.SetOut(PrintStream out)方法,可以設定System.out。

可以看到引數是一個列印流。

設定指定的引數後,Sytem.out.println()就會將內容列印到指定的列印流中。

public class Print {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException{
        System.setOut(new PrintStream(new FileOutputStream(new File("F:\\依風\\Desktop\\print.txt"))));
        System.out.println("setOut");
    }
}

 

還有System.in,這個比較常用的用法就是作為Scanner的引數,表示從鍵盤輸入。

System.in其實就是一個輸入流(InputStream),而System.in預設是鍵盤,這裡可以把鍵盤也看做一個檔案,就是從鍵盤這個檔案讀取內容。

那麼同樣的,我們也可以將System.in修改為其他檔案。

就需要用到System.setIn(InputStream in).這時就是讀取設定之後的輸入流

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;

public class Print {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException{
        //重定向了System.in將原來的將鍵盤輸入更改為其他輸入
        System.setIn(new BufferedInputStream(new FileInputStream(new File("F:\\依風\\Desktop\\print.txt"))));
        Scanner si = new Scanner(System.in);
        System.out.println(si.nextLine());//讀取一行
        
    }
}
執行結果:
setOut//根據檔案內容決定

 

那麼我麼修改了Sytem.in(鍵盤輸入)和System.out(控制檯輸出)為其他的檔案後是否可以還原它們,當然是可以的,之前說了鍵盤、控制檯都是檔案

(在windows中一切都可以看做是檔案),現在的關鍵就是要找到代表控制檯可鍵盤的檔案,然後再次Set就可以了。

我們來看下原始碼:

其中FileDescriptor.in就代表鍵盤,....out就代表控制檯,

public class Print {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException{
        //輸出重定向為指定檔案
        System.setOut(new PrintStream(new FileOutputStream(new File("F:\\依風\\Desktop\\print.txt"))));
        System.out.println("setSystem.outAndSystem.in");
        System.out.close();
        //輸出重定向為控制檯
        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
        //輸入重定向為指定檔案
        System.setIn(new BufferedInputStream(new FileInputStream(new File("F:\\依風\\Desktop\\print.txt"))));
        Scanner si = new Scanner(System.in);
        System.out.println(si.nextLine());//內容輸出控制檯
    }
}
執行結果:
setSystem.outAndSystem.in

 

還有一個System.err也是一個列印流,這個主要用於打印出錯誤資訊。比如:

這些紅色的錯誤資訊就是err打印出來的。

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;

public class Print {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException{
        System.err.println("錯誤資訊");
    }
}

執行結果: