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(newByteArrayInputStream(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("錯誤資訊"); } }
執行結果: