這些流都是功能更爲強大的流,是在基本的流物件的基礎上建立起來的,是對基本流的一種增強,比如能夠高效讀寫的緩衝流,能夠轉換編碼的轉換流,能夠持久化儲存物件的序列化流等等。
緩衝流,也叫高效流,是對4個基本的 流的增強(FileInputStream,FileOutputStream,FileReader,FileWriter),所以也是4個流,按照數據型別分類:
位元組緩衝流:BufferedInputStream,BufferedOutputStream,
字元緩衝流:BufferedReader,BufferedWriter
緩衝流的基本原理,是在建立流物件時,會建立一個內建的預設大小的緩衝區陣列,通過緩衝區讀寫,減少系統IO次數,從而提高讀寫的效率。
構造方法:
構造舉例,程式碼如下:
//緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\圖\\a.txt"));
//緩衝輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\圖\\ab.txt"));
//緩衝流
public class mode1 {
public static void main(String[] args) throws IOException {
//緩衝輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\圖\\小助理封面.jpg"));
//緩衝輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\圖\\小助理封copy.jpg"));
long start = System.currentTimeMillis();
int len;
while((len=bis.read())!=-1){
bos.write(len);
}
bos.flush();
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println(end-start + "毫秒");
}
}
28毫秒
public class mode1 {
public static void main(String[] args) throws IOException {
//基本輸入流
FileInputStream bis = new FileInputStream("D:\\圖\\小助理封面.jpg");
//基本輸出流
FileOutputStream bos = new FileOutputStream("D:\\圖\\小助理封面copy.jpg");
long start = System.currentTimeMillis();
int len;
while((len=bis.read())!=-1){
bos.write(len);
}
bos.flush();
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println(end-start + "毫秒");
}
}
2803毫秒
//使用陣列的方式,更快。
public class mode1 {
public static void main(String[] args) throws IOException {
//緩衝基本輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\圖\\小助理封面.jpg"));
//緩衝基本輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\圖\\小助理封copy.jpg"));
long start = System.currentTimeMillis();
byte[] byt = new byte[1024];
int len;
while((len=bis.read(byt))!=-1){
bos.write(byt);
}
bos.flush();
bis.close();
bos.close();
long end = System.currentTimeMillis();
System.out.println(end-start + "毫秒");
}
}
1毫秒
構造方法:
構造舉例:
BufferedReader br = new BufferedReader(new FileReader("D:\\圖\\小助理封面.jpg"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\圖\\小助理封面copy.jpg"));
字元緩衝流的基本方法與普通字元流呼叫方式一致,不再闡述,我們來看它們具備的特有方法。
public String readLine()
: 讀一行文字。public void newLine()
: 寫一行行分隔符,由系統屬性定義符號。方法演示:
public class mode1 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\圖\\a.txt"));
//BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\圖\\小助理封面copy.jpg"));
String str = br.readLine();
System.out.println(str);
br.close();
}
}
10.親賢臣,遠小人,此先漢所以興隆也;親小人,遠賢臣,此後漢所以傾頹也。
public class mode1 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\圖\\a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\圖\\ab.txt"));
HashMap<String,String> hs = new HashMap<>();
String line;
while((line = br.readLine())!=null){
String[] arr = line.split("\\.");
hs.put(arr[0],arr[1]);
}
System.out.println(hs);
for(String key:hs.keySet()){
String value = hs.get(key);
bw.write(key+"."+value);
bw.newLine();//此處換行newLine()方法
}
bw.flush();
br.close();
bw.close();
}
//原先不按順序
11.先帝在時,每與臣論此事,未嘗不嘆息痛恨於桓、靈也。侍中、尚書、長史、參軍,此悉貞良死節之臣,願陛下親之信之,則漢室之隆,可計日而待也。
12.臣本布衣,躬耕於南陽,苟全性命於亂世,不求聞達於諸侯。
1.先帝創業未半而中道崩殂,今天下三分,益州疲弊,此誠危急存亡之秋也。
2.然侍衛之臣不懈於內,忠志之士忘身於外者,蓋追先帝之殊遇,欲報之於陛下也。
3.誠宜開張聖聽,以光先帝遺德,恢弘志士之氣,不宜妄自菲薄,引喻失義,以塞忠諫之路也。
4.宮中府中,俱爲一體,陟罰臧否,不宜異同。
5.ab周若有作奸犯科及爲忠善者,宜付有司論其刑賞,以昭陛下平明之理,不宜偏私,使內外異法也。
6.侍中、侍郎郭攸之、費禕、董允等,此皆良實,志慮忠純,是以先帝簡拔以遺陛下。
7.愚以爲宮中之事,事無大小,悉以諮之,然後施行,必能裨補闕漏,有所廣益。
8.將軍向寵,性行淑均,曉暢軍事,試用於昔日,先帝稱之曰能,是以衆議舉寵爲督。
9.愚以爲營中之事,悉以諮之,必能使行陣和睦,優劣得所。
10.親賢臣,遠小人,此先漢所以興隆也;親小人,遠賢臣,此後漢所以傾頹也。
計算機中儲存的資訊都是用二進制數表示的,而我們在螢幕上看到的數位、英文、標點符號、漢字等字元是二進制數轉換之後的結果。按照某種規則,將字元儲存到計算機中,稱爲編碼 。反之,將儲存在計算機中的二進制數按照某種規則解析顯示出來,稱爲解碼 。比如說,按照A規則儲存,同樣按照A規則解析,那麼就能顯示正確的文字符號。反之,按照A規則儲存,再按照B規則解析,就會導致亂碼現象。
編碼:能看懂的->二進制
解碼:二進制->能看懂的
字元編碼Character Encoding
** : 就是一套自然語言的字元與二進制數之間的對應規則。
編碼表:生活中文字和計算機中二進制的對應規則
Charset
:也叫編碼表。是一個系統支援的所有字元的集合,包括各國家文字、標點符號、圖形符號、數位等。計算機要準確的儲存和識別各種字元集符號,需要進行字元編碼,一套字元集必然至少有一套字元編碼。常見字元集有ASCII字元集、GBK字元集、Unicode字元集等。
可見,當指定了編碼,它所對應的字元集自然就指定了,所以編碼纔是我們最終要關心的。
ASCII字元集 :
ISO-8859-1字元集:
GBxxx字元集:
Unicode字元集 :
在IDEA中,使用FileReader
讀取專案中的文字檔案。由於IDEA的設定,都是預設的UTF-8
編碼(我的eclipse是GBK有時候會出現亂碼),所以沒有任何問題。但是,當讀取Windows系統中建立的文字檔案時,由於Windows系統的預設是GBK編碼,就會出現亂碼。
轉換流java.io.InputStreamReader
,是Reader的子類,是從位元組流到字元流的橋樑。它讀取位元組,並使用指定的字元集將其解碼爲字元。它的字元集可以由名稱指定,也可以接受平臺的預設字元集。
構造方法
* InputStreamReader(InputStream in): 建立一個使用預設字元集的字元流。
* InputStreamReader(InputStream in, String charsetName): 建立一個指定字元集的字元流。
構造方法舉例:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
指定編碼讀入:
public class mode2 {
public static void main(String[] args) throws IOException, FileNotFoundException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\圖\\b.txt"),"GBK");
int len = 0;
while((len = isr.read())!=-1){
System.out.println((char)len);
}
isr.close();
}
}
你
好
//爲啥你好是四個數
20320
22909
13
10
轉換流java.io.OutputStreamWriter
,是Writer的子類,是從字元流到位元組流的橋樑。使用指定的字元集將字元編碼爲位元組。它的字元集可以由名稱指定,也可以接受平臺的預設字元集。
構造舉例
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");
指定編碼寫出
public class mode2 {
public static void main(String[] args) throws IOException, FileNotFoundException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\圖\\zhou.txt"),"UTF-8");
osw.write("你好漂亮");
osw.flush();
osw.close();
}
}
將GBK編碼的文字檔案,轉換爲UTF-8編碼的文字檔案。
public class mode2 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\圖\\new.txt"),"UTF-8");
OutputStreamWriter isw = new OutputStreamWriter(new FileOutputStream("D:\\圖\\new2.txt"),"GBK");
int len = 0;
while((len=isr.read())!=-1){
System.out.println((char)len);
isw.write(len);
}
isr.close();
isw.flush();
isw.close();
}
}
Java 提供了一種物件序列化的機制 機製。用一個位元組序列可以表示一個物件,該位元組序列包含該物件的數據
、物件的型別
和物件中儲存的屬性
等資訊。位元組序列寫出到檔案之後,相當於檔案中持久儲存了一個物件的資訊。
反之,該位元組序列還可以從檔案中讀取回來,重構物件,對它進行反序列化。物件的數據
、物件的型別
和物件中儲存的數據
資訊,都可以用來在記憶體中建立物件。
public ObjectOutputStream(OutputStream out)
: 建立一個指定OutputStream的ObjectOutputStream。
構造舉例,程式碼如下:
FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
*一個物件要想序列化,必須滿足兩個條件:
該類必須實現java.io.Serializable
介面,Serializable
是一個標記介面,不實現此介面的類將不會使任何狀態序列化或反序列化,會拋出NotSerializableException
。
該類的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須註明是瞬態的,使用transient
關鍵字修飾。
public class Employee implements java.io.Serializable {
public String name;
public String address;
public transient int age; // transient瞬態修飾成員,不會被序列化
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
2.寫出物件方法
public final void writeObject (Object obj)
: 將指定的物件寫出。
public class mode4 {
public static void main(String[] args) throws FileNotFoundException, IOException {
personal per= new personal("小小",21);
ObjectOutputStream oops = new ObjectOutputStream(new FileOutputStream("D://圖//814.txt"));
oops.writeObject(per);
System.out.println(per);
oops.close();
}
}
personal [name=小小, id=21]
ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復爲物件。
public ObjectInputStream(InputStream in)
: 建立一個指定InputStream的ObjectInputStream。如果能找到一個物件的class檔案,我們可以進行反序列化操作,呼叫ObjectInputStream
讀取物件的方法:
public final Object readObject ()
: 讀取一個物件。public class mode5 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("D:\\圖\\814.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
personal e = (personal)ois.readObject();
System.out.println(e);
}
}
personal [name=小小, id=21]
對於JVM可以反序列化物件,它必須是能夠找到class檔案的類。如果找不到該類的class檔案,則拋出一個 ClassNotFoundException
異常。
**另外,當JVM反序列化物件時,能找到class檔案,但是class檔案在序列化物件之後發生了修改,那麼反序列化操作也會失敗,拋出一個InvalidClassException
異常。**發生這個異常的原因如下:
Serializable
介面給需要序列化的類,提供了一個序列版本號。serialVersionUID
該版本號的目的在於驗證序列化的物件和對應類是否版本匹配。
報錯
Exception in thread 「main」 java.io.InvalidClassException: text811.personal; local class incompatible: stream classdesc serialVersionUID = -3623888092351341025, local class serialVersionUID = 1
public class Employee implements java.io.Serializable {
// 加入序列版本號
private static final long serialVersionUID = 1L;
public String name;
public String address;
// 新增新的屬性 ,重新編譯, 可以反序列化,該屬性賦爲預設值.
public int eid;
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
static關鍵字,靜態關鍵字優先於非靜態關鍵字載入到記憶體中(靜態優先於物件進入到記憶體中)
被static修飾的成員變數不能被序列化,序列化的都是物件
private String name;
private static int id;
transient關鍵字:瞬態關鍵字
被transient修飾成員變數,不能被序列化,功能與static一樣,但他不是靜態
private String name;
private transient int id;
被static或transient修飾的成員變數反序列化時值會爲成員變數的預設值。
list.txt
檔案中。list.txt
,並遍歷集合,列印物件資訊。public class mode6 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ArrayList<personal> as = new ArrayList<>();
ArrayList<personal> aq = new ArrayList<>();
personal per1 = new personal("小周",21);
personal per2 = new personal("小趙",22);
personal per3 = new personal("小王",23);
as.add(per1);
as.add(per2);
as.add(per3);
FileOutputStream fos = new FileOutputStream("D:\\圖\\Student.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(as);
FileInputStream fis = new FileInputStream("D:\\圖\\Student.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
aq = (ArrayList<personal>)ois.readObject();
for(int len=0;len<aq.size();len++){
System.out.println(aq.get(len));
}
fis.close();
fos.close();
oos.close();
ois.close();
}
結果輸出
personal [name=小周, id=21]
personal [name=小趙, id=22]
personal [name=小王, id=23]
平時我們在控制檯列印輸出,是呼叫print
方法和println
方法完成的,這兩個方法都來自於java.io.PrintStream
類,該類能夠方便地列印各種數據型別的值,是一種便捷的輸出方式。
public PrintStream(String fileName)
: 使用指定的檔名建立一個新的列印流。構造舉例,程式碼如下:
PrintStream ps = new PrintStream("ps.txt");
System.out
就是PrintStream
型別的,只不過它的流向是系統規定的,列印在控制檯上。不過,既然是流物件,改變它的流向。
public class mode {
public static void main(String[] args) throws FileNotFoundException {
System.out.println(97);
PrintStream ps = new PrintStream("D:\\圖\\ps.txt");
System.setOut(ps);
System.out.println(97);
}
}