今日內容
- IO異常處理---->必須掌握
- jdk7前處理方式
- jdk7的處理方式
- Properties類---->必須掌握
- 高級流
- 緩沖流---->必須掌握
- 字節緩沖流
- 字符緩沖流
- 轉換流---->必須掌握
- 轉換輸入流
- 轉換輸出流
- 序列化流
- 反序列化流
- 打印流
- 緩沖流---->必須掌握
- 裝飾者模式---->必須掌握
- commons-io工具包---->必須掌握
第一章 IO資源的處理
1.1 JDK7前處理
之前的入門練習,我們一直把異常拋出,而實際開發中并不能這樣處理,建議使用try...catch...finally 代碼塊,處理異常部分,代碼使用演示:
/**
* Created by PengZhiLin on 2021/8/12 9:02
*/
public class Test1_JDK7前處理 {
public static void main(String[] args) {
// jdk7之前IO異常處理:try...catch...finally
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1.創建字節輸入流對象,關聯數據源文件路徑
fis = new FileInputStream("day11\\aaa\\hb.jpg");
// 2.創建字節輸出流對象,關聯目的地文件路徑
fos = new FileOutputStream("day11\\aaa\\hbCopy1.jpg");
// 3.定義一個byte數組,用來存儲讀取到的字節數據
byte[] bytes = new byte[8192];
// 3.定義一個int變量,用來存儲讀取到的字節個數
int len;
// 4.循環讀數據
while ((len = fis.read(bytes)) != -1) {
// 5.在循環中,寫數據
fos.write(bytes, 0, len);
}
} catch (IOException e) {
System.out.println("發生了異常:" + e.getMessage());
} finally {
// 6.關閉流,釋放資源
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.2 JDK7的處理
還可以使用JDK7優化后的try-with-resource 語句,該語句確保了每個資源在語句結束時自動關閉。所謂的資源(resource)是指在程序完成后,必須關閉的對象。
格式:
try (創建流對象語句,如果多個,使用';'隔開) {
// 讀寫數據
} catch (IOException e) {
e.printStackTrace();
}
代碼使用演示:
/**
* Created by PengZhiLin on 2021/8/12 9:20
*/
public class Test2_JDK7的處理 {
public static void main(String[] args) {
// jdk7的IO異常處理: try...with.resource
try (
// 1.創建字節輸入流對象,關聯數據源文件路徑
FileInputStream fis = new FileInputStream("day11\\aaa\\hb.jpg");
// 2.創建字節輸出流對象,關聯目的地文件路徑
FileOutputStream fos = new FileOutputStream("day11\\aaa\\hbCopy2.jpg");
) {
// 3.定義一個byte數組,用來存儲讀取到的字節數據
byte[] bytes = new byte[8192];
// 3.定義一個int變量,用來存儲讀取到的字節個數
int len;
// 4.循環讀數據
while ((len = fis.read(bytes)) != -1) {
// 5.在循環中,寫數據
fos.write(bytes, 0, len);
}
// 6.關閉流,釋放資源
//fos.close();
//fis.close();
} catch (Exception e) {
System.out.println("發生了異常:" + e.getMessage());
}
}
}
第二章 屬性集
2.1 Properties類
-
概述:
- Properties類繼承Hashtable,而Hashtable實現了Map接口,所以Properties本質其實就是一個Map集合,可以使用Map接口中的所有方法,但一般不把Properties當成Map集合使用
- Properties也是一個屬性集,可以用來加載文件中的數據(鍵值對的形式存儲), 并且Properties屬性集中每個鍵及其對應值都是一個字符串。
-
構造方法
public Properties()創建一個空的屬性集對象
-
存儲方法
public Object setProperty(String key, String value) 保存一對屬性。 public String getProperty(String key) 使用此屬性列表中指定的鍵搜索屬性值。 public Set<String> stringPropertyNames() 所有鍵的名稱的集合。/** * Created by PengZhiLin on 2021/8/12 9:39 */ public class Test1 { public static void main(String[] args) { // 1.創建Properties對象 Properties pro = new Properties(); // 2.添加鍵值對到Properties對象中 pro.setProperty("k1", "v1"); pro.setProperty("k2", "v2"); pro.setProperty("k3", "v3"); // 3.獲取所有的鍵 Set<String> keys = pro.stringPropertyNames(); // 4.循環遍歷所有的鍵 for (String key : keys) { // 根據鍵找值 String value = pro.getProperty(key); System.out.println(key + "," + value); } } } -
與流相關的方法
-
public void load(InputStream is);加載配置文件中的鍵值對,存儲到Properties對象中 -
public void load(Reader r);加載配置文件中的鍵值對,存儲到Properties對象中 -
注意:
- 如果文件中沒有中文,就使用第一個load方法
- 如果文件中有中文,就使用第二個load方法
- 開發中配置文件一般沒有中文
-
案例:
/** * Created by PengZhiLin on 2021/8/12 9:45 */ public class Test2 { public static void main(String[] args) throws Exception { // 1.創建Properties對象 Properties pro = new Properties(); // 2.調用load方法加載文件 pro.load(new FileInputStream("day11\\aaa\\a.txt")); //pro.load(new FileReader("day11\\aaa\\a.txt")); // 3.獲取所有的鍵 Set<String> keys = pro.stringPropertyNames(); // 4.遍歷所有的鍵 for (String key : keys) { // 5.根據鍵找值 String value = pro.getProperty(key); System.out.println(key+","+value); } } }
-
第三章 緩沖流
昨天學習了基本的一些流,作為IO流的入門,今天我們要見識一些更強大的流。比如能夠高效讀寫的緩沖流,能夠轉換編碼的轉換流,能夠持久化存儲對象的序列化流等等。這些功能更為強大的流,都是在基本的流對象基礎之上創建而來的,就像穿上鎧甲的武士一樣,相當于是對基本流對象的一種增強。
3.1 緩沖流
緩沖流,也叫高效流,是對4個基本的FileXxx 流的增強,所以也是4個流,按照數據類型分類:
- 字節緩沖流:
BufferedInputStream,BufferedOutputStream - 字符緩沖流:
BufferedReader,BufferedWriter
緩沖流的基本原理,是在創建流對象時,會創建一個內置的默認大小的緩沖區數組,通過緩沖區讀寫,減少系統IO次數,從而提高讀寫的效率。
3.2 字節緩沖流
-
構造方法
- BufferedInputStream類:
public BufferedInputStream(InputStream is); - BufferedOutputStream類:
public BufferedOutputStream(OutputStream os);
- BufferedInputStream類:
-
拷貝文件效率測試
-
注意: 字節緩沖流沒有特有的功能,讀和寫的功能都來自于他們的父類(InputStream , OutputStream)
-
普通字節流一次讀寫一個字節拷貝文件
/** * Created by PengZhiLin on 2021/8/12 9:53 */ public class Test1_普通字節流一次讀寫一個字節拷貝文件 { public static void main(String[] args) throws Exception{ // 0.拷貝開始時間 long start = System.currentTimeMillis(); // 1.創建字節輸入流對象,關聯數據源文件路徑 FileInputStream fis = new FileInputStream("day11\\aaa\\jdk9.exe"); // 2.創建字節輸出流對象,關聯目的地文件路徑 FileOutputStream fos = new FileOutputStream("day11\\aaa\\jdk9Copy1.exe"); // 3.定義一個int變量,用來存儲讀取到的字節數據 int b; // 4.循環讀 while ((b = fis.read()) != -1) { // 5.寫數據 fos.write(b); } // 6.關閉流,釋放資源 fos.close(); fis.close(); // 7.拷貝開始時間 long end = System.currentTimeMillis(); System.out.println("總共花了:"+(end - start)+"毫秒");// 至少十幾分鐘 }
}
-
-
字節緩沖流一次讀寫一個字節拷貝文件
/** * Created by PengZhiLin on 2021/8/12 9:53 */ public class Test2_字節緩沖流一次讀寫一個字節拷貝文件 { public static void main(String[] args) throws Exception{ // 0.拷貝開始時間 long start = System.currentTimeMillis(); // 1.創建字節緩沖輸入流對象,關聯數據源文件路徑 FileInputStream fis = new FileInputStream("day11\\aaa\\jdk9.exe"); BufferedInputStream bis = new BufferedInputStream(fis); // 2.創建字節緩沖輸出流對象,關聯目的地文件路徑 FileOutputStream fos = new FileOutputStream("day11\\aaa\\jdk9Copy2.exe"); BufferedOutputStream bos = new BufferedOutputStream(fos); // 3.定義一個int變量,用來存儲讀取到的字節數據 int b; // 4.循環讀 while ((b = bis.read()) != -1) { // 5.寫數據 bos.write(b); } // 6.關閉流,釋放資源 bos.close(); bis.close(); // 7.拷貝開始時間 long end = System.currentTimeMillis(); System.out.println("總共花了:"+(end - start)+"毫秒");// 大概28秒 } }-
字節緩沖流一次讀寫一個字節數組拷貝文件
/** * Created by PengZhiLin on 2021/8/12 9:53 */ public class Test3_字節緩沖流一次讀寫一個字節數組拷貝文件 { public static void main(String[] args) throws Exception{ // 0.拷貝開始時間 long start = System.currentTimeMillis(); // 1.創建字節緩沖輸入流對象,關聯數據源文件路徑 FileInputStream fis = new FileInputStream("day11\\aaa\\jdk9.exe"); BufferedInputStream bis = new BufferedInputStream(fis); // 2.創建字節緩沖輸出流對象,關聯目的地文件路徑 FileOutputStream fos = new FileOutputStream("day11\\aaa\\jdk9Copy3.exe"); BufferedOutputStream bos = new BufferedOutputStream(fos); // 3.定義一個int變量,用來存儲讀取到的字節數據 byte[] bys = new byte[8192]; // 3.定義一個int變量,用來存儲讀取到的字節個數 int len; // 4.循環讀 while ((len = bis.read(bys)) != -1) { // 5.寫數據 bos.write(bys,0,len); } // 6.關閉流,釋放資源 bos.close(); bis.close(); // 7.拷貝開始時間 long end = System.currentTimeMillis(); System.out.println("總共花了:"+(end - start)+"毫秒");// 大概5秒 } }
-
3.3 緩沖流讀寫效率高的基本原理
緩沖流的基本原理,是在創建流對象時,會創建一個內置的默認大小的緩沖區數組,通過緩沖區讀寫,減少系統IO次數,從而提高讀寫的效率。

3.4 字符緩沖流
-
字符緩沖流的構造方法
- BufferedReader類:
public BufferedReader(Reader r);創建一個字符緩沖輸入流對象 - BufferedWriter類:
public BufferedWriter(Writer w);創建一個字符緩沖輸出流對象
- BufferedReader類:
-
字符緩沖流的特有方法
-
BufferedReader類繼承Reader類,所以也擁有了Reader類中的所有方法,但自己還有特有的方法:
-
public String readLine(); 讀取一行數據,讀取到文件的末尾返回null文件中的數據: 看這風景美如畫 本想吟詩贈天下 奈何本人沒文化 一句我操浪好大 /** * Created by PengZhiLin on 2021/8/12 10:20 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建BufferedReader對象 BufferedReader br = new BufferedReader(new FileReader("day11\\aaa\\b.txt")); // 2.讀一行 //System.out.println(br.readLine()); //System.out.println(br.readLine()); //System.out.println(br.readLine()); //System.out.println(br.readLine()); //System.out.println(br.readLine()); // 定義一個String類型的變量 String line; while ((line = br.readLine()) != null){ System.out.println(line); } // 3.關閉流,釋放資源 br.close(); } }
-
-
BufferedWriter類繼承Writer類,所以也擁有了Writer類中的所有方法,但自己還有特有的方法:
-
public void newLine(); 根據系統寫一個行分隔符/** * Created by PengZhiLin on 2021/8/12 10:24 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建字符緩沖輸出流對象,關聯目的地文件路徑 BufferedWriter bw = new BufferedWriter(new FileWriter("day11\\aaa\\c.txt")); // 2.寫數據 bw.write("看這風景美如畫"); bw.newLine(); bw.write("本想吟詩贈天下"); bw.newLine(); bw.write("奈何本人沒文化"); bw.newLine(); bw.write("一句我操浪好大"); // 3.關閉流,釋放資源 bw.close(); }
-
}
``` -
3.5 文本排序
需求
請將文本信息恢復順序。
3.侍中、侍郎郭攸之、費祎、董允等,此皆良實,志慮忠純,是以先帝簡拔以遺陛下。愚以為宮中之事,事無大小,悉以咨之,然后施行,必得裨補闕漏,有所廣益。
8.愿陛下托臣以討賊興復之效,不效,則治臣之罪,以告先帝之靈。若無興德之言,則責攸之、祎、允等之慢,以彰其咎;陛下亦宜自謀,以咨諏善道,察納雅言,深追先帝遺詔,臣不勝受恩感激。
4.將軍向寵,性行淑均,曉暢軍事,試用之于昔日,先帝稱之曰能,是以眾議舉寵為督。愚以為營中之事,悉以咨之,必能使行陣和睦,優劣得所。
2.宮中府中,俱為一體,陟罰臧否,不宜異同。若有作奸犯科及為忠善者,宜付有司論其刑賞,以昭陛下平明之理,不宜偏私,使內外異法也。
1.先帝創業未半而中道崩殂,今天下三分,益州疲弊,此誠危急存亡之秋也。然侍衛之臣不懈于內,忠志之士忘身于外者,蓋追先帝之殊遇,欲報之于陛下也。誠宜開張圣聽,以光先帝遺德,恢弘志士之氣,不宜妄自菲薄,引喻失義,以塞忠諫之路也。
9.今當遠離,臨表涕零,不知所言。
6.臣本布衣,躬耕于南陽,茍全性命于亂世,不求聞達于諸侯。先帝不以臣卑鄙,猥自枉屈,三顧臣于草廬之中,咨臣以當世之事,由是感激,遂許先帝以驅馳。后值傾覆,受任于敗軍之際,奉命于危難之間,爾來二十有一年矣。
7.先帝知臣謹慎,故臨崩寄臣以大事也。受命以來,夙夜憂嘆,恐付托不效,以傷先帝之明,故五月渡瀘,深入不毛。今南方已定,兵甲已足,當獎率三軍,北定中原,庶竭駑鈍,攘除奸兇,興復漢室,還于舊都。此臣所以報先帝而忠陛下之職分也。至于斟酌損益,進盡忠言,則攸之、祎、允之任也。
5.親賢臣,遠小人,此先漢所以興隆也;親小人,遠賢臣,此后漢所以傾頹也。先帝在時,每與臣論此事,未嘗不嘆息痛恨于桓、靈也。侍中、尚書、長史、參軍,此悉貞良死節之臣,愿陛下親之信之,則漢室之隆,可計日而待也。
分析
分析
1.創建字符緩沖輸入流對象,關聯數據源文件路徑
2.創建ArrayList集合,集合元素類型為String
3.定義一個String類型的變量,用來存儲讀取到的行數據
4.循環讀行數據
5.把讀到的行數據存儲到ArrayList集合中
6.關閉流,釋放資源
7.對ArrayList集合進行排序
8.創建字符緩沖輸出流對象,關聯目的地文件路徑
9.循環遍歷ArrayList集合
10.在循環中,寫數據,寫換行
11.關閉流,釋放資源
實現
/**
* Created by PengZhiLin on 2021/8/12 10:45
*/
public class Test {
public static void main(String[] args) throws Exception {
//1.創建字符緩沖輸入流對象,關聯數據源文件路徑
BufferedReader br = new BufferedReader(new FileReader("day11\\aaa\\d.txt"));
//2.創建ArrayList集合,集合元素類型為String
ArrayList<String> list = new ArrayList<>();
//3.定義一個String類型的變量,用來存儲讀取到的行數據
String line;
//4.循環讀行數據
while ((line = br.readLine()) != null) {
//5.把讀到的行數據存儲到ArrayList集合中
list.add(line);
}
//6.關閉流,釋放資源
br.close();
//7.對ArrayList集合進行排序
Collections.sort(list);
/*for (String s : list) {
System.out.println(s);
}*/
//8.創建字符緩沖輸出流對象,關聯目的地文件路徑
BufferedWriter bw = new BufferedWriter(new FileWriter("day11\\aaa\\d.txt"));
//9.循環遍歷ArrayList集合
for (String s : list) {
//10.在循環中,寫數據,寫換行
bw.write(s);
bw.newLine();
}
//11.關閉流,釋放資源
bw.close();
}
}
第四章 轉換流
4.1 字符編碼和字符集
字符編碼的概述
計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換之后的結果。按照某種規則,將字符存儲到計算機中,稱為編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼 。比如說,按照A規則存儲,同樣按照A規則解析,那么就能顯示正確的文本f符號。反之,按照A規則存儲,再按照B規則解析,就會導致亂碼現象。
- 字符編碼
Character Encoding: 就是一套自然語言的字符與二進制數之間的對應規則。
字符集的概述
- 字符集
Charset:也叫編碼表。是一個系統支持的所有字符的集合,包括各國家文字、標點符號、圖形符號、數字等。
計算機要準確的存儲和識別各種字符集符號,需要進行字符編碼,一套字符集必然至少有一套字符編碼。常見字符集有ASCII字符集、GBK字符集、Unicode字符集等。
可見,當指定了編碼,它所對應的字符集自然就指定了,所以編碼才是我們最終要關心的。
- ASCII字符集 :
- ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)是基于拉丁字母的一套電腦編碼系統,用于顯示現代英語,主要包括控制字符(回車鍵、退格、換行鍵等)和可顯示字符(英文大小寫字符、阿拉伯數字和西文符號)。
- 基本的ASCII字符集,使用7位(bits)表示一個字符,共128字符。ASCII的擴展字符集使用8位(bits)表示一個字符,共256字符,方便支持歐洲常用字符。
- ISO-8859-1字符集:
- 拉丁碼表,別名Latin-1,用于顯示歐洲使用的語言,包括荷蘭、丹麥、德語、意大利語、西班牙語等。
- ISO-5559-1使用單字節編碼,兼容ASCII編碼。
- GBxxx字符集:
- GB就是國標的意思,是為了顯示中文而設計的一套字符集。
- GB2312:簡體中文碼表。一個小于127的字符的意義與原來相同。但兩個大于127的字符連在一起時,就表示一個漢字,這樣大約可以組合了包含7000多個簡體漢字,此外數學符號、羅馬希臘的字母、日文的假名們都編進去了,連在ASCII里本來就有的數字、標點、字母都統統重新編了兩個字節長的編碼,這就是常說的"全角"字符,而原來在127號以下的那些就叫"半角"字符了。
- GBK:最常用的中文碼表。是在GB2312標準基礎上的擴展規范,使用了雙字節編碼方案,共收錄了21003個漢字,完全兼容GB2312標準,同時支持繁體漢字以及日韓漢字等。
- GB18030:最新的中文碼表。收錄漢字70244個,采用多字節編碼,每個字可以由1個、2個或4個字節組成。支持中國國內少數民族的文字,同時支持繁體漢字以及日韓漢字等。
- Unicode字符集 :
- Unicode編碼系統為表達任意語言的任意字符而設計,是業界的一種標準,也稱為統一碼、標準萬國碼。
- 它最多使用4個字節的數字來表達每個字母、符號,或者文字。有三種編碼方案,UTF-8、UTF-16和UTF-32。最為常用的UTF-8編碼。
- UTF-8編碼,可以用來表示Unicode標準中任何字符,它是電子郵件、網頁及其他存儲或傳送文字的應用中,優先采用的編碼。互聯網工程工作小組(IETF)要求所有互聯網協議都必須支持UTF-8編碼。所以,我們開發Web應用,也要使用UTF-8編碼。它使用一至四個字節為每個字符編碼,編碼規則:
- 128個US-ASCII字符,只需一個字節編碼。
- 拉丁文等字符,需要二個字節編碼。
- 大部分常用字(含中文),使用三個字節編碼。
- 其他極少使用的Unicode輔助字符,使用四字節編碼。
4.2 編碼引出的問題
-
FileReader讀取utf8編碼的文件,中文不會亂碼---->idea默認是utf8
-
FileReader讀取gbk編碼的文件,中文就會亂碼
/** * Created by PengZhiLin on 2021/8/12 11:05 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建字符輸入流對象,關聯數據源文件路徑 FileReader fr = new FileReader("day11\\bbb\\gbk.txt"); // 2.定義一個int變量,用來存儲讀取到的字符數據 int c; // 3.循環讀 while ((c = fr.read()) != -1){ System.out.println((char)c);// 亂碼 } // 4.關閉流,釋放資源 fr.close(); } }
## 4.3 InputStreamReader類
- 概述: java.io.InputStreamReader類繼承Reader類,所以也是字符輸入流,可以用來讀字符數據
- 作用:
- 1.可以將字節輸入流轉換為字符輸入流
- 2.可以指定編碼讀數據
- 構造方法:
- `public InputStreamReader(InputStream is);創建一個轉換輸入流對象,使用平臺默認字符集`
- `public InputStreamReader(InputStream is,String charsetName);創建一個轉換輸入流對象,指定字符集` ------>掌握
```java
/**
* Created by PengZhiLin on 2021/8/12 11:13
*/
public class Test1_構造方法 {
public static void main(String[] args) throws Exception{
// - `public InputStreamReader(InputStream is);創建一個轉換輸入流對象,使用平臺默認字符集` idea默認是utf8
InputStreamReader isr1 = new InputStreamReader(new FileInputStream("day11\\bbb\\utf8.txt"));// 不亂碼
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("day11\\bbb\\gbk.txt"));// 亂碼
//- `public InputStreamReader(InputStream is,String charsetName);創建一個轉換輸入流對象,指定字符集` ------>掌握
InputStreamReader isr3 = new InputStreamReader(new FileInputStream("day11\\bbb\\utf8.txt"),"utf-8");// 不亂碼
InputStreamReader isr4 = new InputStreamReader(new FileInputStream("day11\\bbb\\gbk.txt"),"gbk");// 不亂碼
}
}
```
- 指定編碼讀取
- 讀gbk編碼文件
```java
/**
* Created by PengZhiLin on 2021/8/12 11:18
*/
public class Test2_指定gbk編碼讀gbk編碼的文件 {
public static void main(String[] args) throws Exception{
// 1.創建轉換輸入流對象,關聯數據源文件路徑,指定gbk編碼
InputStreamReader isr = new InputStreamReader(new FileInputStream("day11\\bbb\\gbk.txt"),"gbk");
// 2.定義一個int變量,用來存儲讀取到的字符數據
int c;
// 3.循環讀數據
while ((c = isr.read()) != -1){
System.out.println((char)c);
}
// 4.關閉流,釋放資源
isr.close();
}
}
```
- 讀utf8編碼文件
```java
/**
* Created by PengZhiLin on 2021/8/12 11:18
*/
public class Test3_指定utf8編碼讀utf8編碼的文件 {
public static void main(String[] args) throws Exception{
// 1.創建轉換輸入流對象,關聯數據源文件路徑,指定utf8編碼
InputStreamReader isr = new InputStreamReader(new FileInputStream("day11\\bbb\\utf8.txt"),"utf8");
// 2.定義一個int變量,用來存儲讀取到的字符數據
int c;
// 3.循環讀數據
while ((c = isr.read()) != -1){
System.out.println((char)c);
}
// 4.關閉流,釋放資源
isr.close();
}
}
```
## 4.4 OutputStreamWriter類
- 概述: java.io.OutputStreamWriter類繼承Writer類,所以也是字符輸出流,可以用來寫字符數據
- 作用:
- 1.可以將字節輸出流轉換為字符輸出流
- 2.可以指定編碼寫數據
- 構造方法:
- `public OutputStreamWriter(OutputStream os);創建轉換輸出流對象,使用平臺默認字符集`
- `public OutputStreamWriter(OutputStream os,String charsetName);創建轉換輸出流對象,指定字符集` ------>掌握,常用
- 指定編碼寫數據
- 指定gbk編碼寫出數據
```java
/**
* Created by PengZhiLin on 2021/8/12 11:37
*/
public class Test1_指定gbk編碼寫數據 {
public static void main(String[] args)throws Exception{
// 1.創建轉換輸出流對象,關聯目的地文件路徑,指定gbk編碼
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day11\\bbb\\gbk_1.txt"),"gbk");
// 2.寫數據
osw.write("中國很棒");
// 3.釋放資源
osw.close();
}
}
-
指定utf8編碼寫出數據
/** * Created by PengZhiLin on 2021/8/12 11:37 */ public class Test2_指定utf8編碼寫數據 { public static void main(String[] args)throws Exception{ // 1.創建轉換輸出流對象,關聯目的地文件路徑,指定utf8編碼 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day11\\bbb\\utf8_1.txt"),"utf-8"); // 2.寫數據 osw.write("中國很棒"); // 3.釋放資源 osw.close(); } }
4.5 轉換文件編碼
需求
- 將GBK編碼的文本文件,轉換為UTF-8編碼的文本文件。
分析
- 指定GBK編碼的轉換流,讀取文本文件。
- 使用UTF-8編碼的轉換流,寫出文本文件。
實現
/**
* Created by PengZhiLin on 2021/8/12 11:44
*/
public class Test {
public static void main(String[] args)throws Exception {
// 1.創建轉換輸入流對象,關聯數據源文件路徑,指定gbk編碼
InputStreamReader isr = new InputStreamReader(new FileInputStream("day11\\bbb\\gbk_1.txt"),"gbk");
// 2.創建轉換輸出流對象,關聯目的地文件路徑,指定utf8編碼
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day11\\bbb\\gbk_utf8.txt"),"utf8");
// 3.定義一個int變量,用來存儲讀取到的字符數據
int c;
// 4.循環讀
while ((c = isr.read()) != -1) {
// 5.寫數據
osw.write(c);
}
// 6.釋放資源
osw.close();
isr.close();
}
}
第五章 序列化
5.1 序列化和反序列化的概念
Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據、對象的類型和對象中存儲的屬性等信息。字節序列寫出到文件之后,相當于文件中持久保存了一個對象的信息。
反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化。對象的數據、對象的類型和對象中存儲的數據信息,都可以用來在內存中創建對象。看圖理解序列化: 
5.2 ObjectOutputStream類
-
概述: java.io.ObjectOutputStream類繼承OutputStream,所以是一個字節輸出流,可以用來寫出字節數據,并且可以寫Java對象
-
構造方法
public ObjectOutputStream(OutputStream out);創建序列化流對象,傳入字節輸出流
-
序列化操作---->寫對象到文件中,變成字節數據
public void wirteObject(Object obj);寫一個對象(序列化操作)
-
注意: 被序列化的對象所屬的類一定要實現Serializable接口(標記接口)
-
案例:
/** * Created by PengZhiLin on 2021/8/12 12:13 */ // 被序列化的對象所屬的類一定要實現Serializable接口(標記接口) public class Person implements Serializable {// String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }/** * Created by PengZhiLin on 2021/8/12 12:13 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建Person對象 Person p = new Person("張三",18); // 2.創建序列化流對象,關聯目的地文件路徑 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day11\\ccc\\person.txt")); // 3.寫對象 oos.writeObject(p); // 4.關閉流,釋放資源 oos.close(); } }
5.3 ObjectInputStream類
-
概述: java.io.ObjectInputStream類繼承InputStream,所以是一個字節輸入流,可以用來讀字節數據,并且可以讀Java對象
-
構造方法
public ObjectInputStream(InputStream in);創建反序列化流對象,傳入字節輸入流
-
反序列化操作
public Object readObject();重構一個對象
-
案例:
/** * Created by PengZhiLin on 2021/8/12 12:19 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建反序列化流對象,關聯數據源文件路徑 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day11\\ccc\\person.txt")); // 2.重構對象 //Object obj = ois.readObject(); Person p = (Person)ois.readObject(); // 3.關閉流,釋放資源 ois.close(); //System.out.println(obj);// Person{name='張三', age=18} System.out.println(p);// Person{name='張三', age=18} } }
5.4 序列化和反序列化注意事項
-
序列化的注意事項
-
被序列化的對象所屬的類一定要實現Serializable接口(標記接口)
-
被序列化的對象所有的屬性也是要可以被序列化的
-
如果別序列化的對象的屬性不想被序列化,那么該屬性就需要使用transient關鍵字修飾,表示瞬態
/** * Created by PengZhiLin on 2021/8/12 14:32 */ //- 被序列化的對象所屬的類一定要實現Serializable接口(標記接口) public class Person implements Serializable { //- 被序列化的對象所有的屬性也是要可以被序列化的 String name; Pet pet;// 寵物 Pet類實現序列化接口Serializable //- 如果別序列化的對象的屬性不想被序列化,那么該屬性就需要使用transient關鍵字修飾,表示瞬態 transient int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", pet=" + pet + '}'; } }/** * Created by PengZhiLin on 2021/8/12 14:33 */ public class Pet implements Serializable { String name; public Pet(String name) { this.name = name; } @Override public String toString() { return "Pet{" + "name='" + name + '\'' + '}'; } }
-
-
反序列化的注意事項
-
1.如果要反序列化成功,一定要能夠找到該類的class文件,否則反序列化會失敗
-
2.如果能找到該類的class文件,但序列化后又修改了類,這個時候也會反序列化失敗-->解決加版本號
//- 被序列化的對象所屬的類一定要實現Serializable接口(標記接口) public class Person implements Serializable { //- 被序列化的對象所有的屬性也是要可以被序列化的 String name; Pet pet;// 寵物 Pet類實現序列化接口Serializable //- 如果別序列化的對象的屬性不想被序列化,那么該屬性就需要使用transient關鍵字修飾,表示瞬態 transient int age; // 序列化版本號 static final long serialVersionUID = 8L; String sex; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", pet=" + pet + '}'; } }/** * Created by PengZhiLin on 2021/8/12 14:31 */ public class Test1_序列化 { public static void main(String[] args) throws Exception{ // 1.創建Person對象 Person p = new Person("張三",18); p.pet = new Pet("旺財"); // 2.創建序列化流對象,關聯目的地文件路徑 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day11\\ccc\\person1.txt")); // 3.序列化對象 oos.writeObject(p); // 4.關閉流,釋放資源 oos.close(); } }/** * Created by PengZhiLin on 2021/8/12 14:36 */ public class Test2_反序列化 { public static void main(String[] args) throws Exception{ // 1.創建反序列化流對象,關聯數據源文件路徑 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day11\\ccc\\person1.txt")); // 2.重構對象 Person p = (Person) ois.readObject(); System.out.println(p); // 3.關閉流,釋放資源 ois.close(); } }
-
5.5 序列化集合
需求
- 將存有多個自定義對象的集合序列化操作,保存到
list.txt文件中。 - 反序列化
list.txt,并遍歷集合,打印對象信息。
實現
-
Person類
/** * Created by PengZhiLin on 2021/8/12 12:13 */ public class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } -
序列化
/** * Created by PengZhiLin on 2021/8/12 15:12 */ public class Test { public static void main(String[] args) throws Exception{ // 1.創建多個Person對象 Person p1 = new Person("張三",18); Person p2 = new Person("李四",28); Person p3 = new Person("王五",38); Person p4 = new Person("趙六",48); // 2.創建ArrayList集合,集合元素類型為Person ArrayList<Person> list = new ArrayList<>(); list.add(p1); list.add(p2); list.add(p3); list.add(p4); // 3.創建序列化流對象,關聯目的地文件路徑 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day11\\ccc\\list.txt")); // 4.序列化集合 oos.writeObject(list); // 5.關閉流,釋放資源 oos.close(); } } -
反序列化
/** * Created by PengZhiLin on 2021/8/12 15:15 */ public class Test2 { public static void main(String[] args) throws Exception{ // 1.創建反序列化流對象,關聯數據源文件路徑 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day11\\ccc\\list.txt")); // 2.重構對象 ArrayList<Person> list = (ArrayList<Person>)ois.readObject(); // 3.關閉流,釋放資源 ois.close(); // 4.遍歷集合 for (Person p : list) { System.out.println(p); } }
}
# 第六章 打印流
- 概述: java.io.PrintStream類繼承OutputStream,也是一個字節輸出流,可以用來寫出字節數據
- 作用: **可以方便打印輸出各種類型的數據**
- 使用:
- 構造方法:
- `public PrintStream(String fileName);創建一個打印流對象,通過參數關聯目的地文件路徑`
- 成員方法:
- `public void print(任意類型);打印任意類型的數據到目的地文件中,打印完不換行`
- `public void println(任意類型);打印任意類型的數據到目的地文件中,打印完換行`
- 案例:
```java
/**
* Created by PengZhiLin on 2021/8/12 15:25
*/
public class Test1 {
public static void main(String[] args) throws Exception{
// 需求: 打印各種類型的數據
// 1.創建打印流對象,關聯目的地文件路徑
PrintStream ps = new PrintStream("day11\\ccc\\a.txt");
// 2.打印各種類型的數據
ps.println(true);
ps.println(97);
ps.println(3.14);
ps.println('a');
ps.println("中國");
// 3.關閉流,釋放資源
ps.close();
}
}
```
```java
/**
* Created by PengZhiLin on 2021/8/12 15:28
*/
public class Test2 {
public static void main(String[] args)throws Exception{
System.out.println("打印輸出是到控制臺1");
// 上面這句代碼等價于下面的代碼
PrintStream ps = System.out;// 獲取System類中的打印流對象
ps.println("打印輸出是到控制臺2");
// 玩個游戲: 修改System類的打印流對象
// 創建打印流對象
PrintStream ps1 = new PrintStream("day11\\ccc\\b.txt");
// 修改System類的打印流對象
System.setOut(ps1);
System.out.println("打印輸出是到控制臺3");//
}
}
```
# 第七章 裝飾設計模式
#### 裝飾模式概述
在我們今天所學的緩沖流中涉及到java的一種設計模式,叫做裝飾模式,我們來認識并學習一下這個設計模式。
**裝飾模式指的是在不改變原類, 不使用繼承的基礎上,動態地擴展一個對象的功能。**
**裝飾模式遵循原則:**
1. 裝飾類和被裝飾類必須實現相同的接口
2. 在裝飾類中必須傳入被裝飾類的引用
3. 在裝飾類中對需要擴展的方法進行擴展
4. 在裝飾類中對不需要擴展的方法調用被裝飾類中的同名方法
#### 案例演示
##### 準備環境:
1. 編寫一個Star接口, 提供sing 和 dance抽象方法
2. 編寫一個LiuDeHua類,實現Star接口,重寫抽象方法
```java
public interface Star {
public void sing();
public void dance();
}
public class LiuDeHua implements Star {
@Override
public void sing() {
System.out.println("劉德華在唱忘情水...");
}
@Override
public void dance() {
System.out.println("劉德華在跳街舞...");
}
}
需求:
? 在不改變原類,不使用繼承重寫的基礎上對LiuDeHua類的sing方法進行擴展,dace方法不擴展
實現步驟:
/**
* Created by PengZhiLin on 2021/8/12 15:52
*/
// 裝飾類
public class LiuDeHuaWrapper implements Star{
// 1.裝飾類與被裝飾類必須實現相同的接口
// 2.在裝飾類中必須傳入被裝飾類的引用
LiuDeHua liuDeHua;
public LiuDeHuaWrapper(LiuDeHua liuDeHua) {
this.liuDeHua = liuDeHua;
}
@Override
public void sing() {
// 需求增強: 增強
System.out.println("劉德華在唱忘情水...");
System.out.println("劉德華在唱笨小孩...");
System.out.println("劉德華在唱練習...");
System.out.println("劉德華在唱愛你一萬年...");
System.out.println("劉德華在唱冰雨...");
}
@Override
public void dance() {
// 不需要增強: 調用被裝飾類中同名的方法
liuDeHua.dance();
}
}
/**
* Created by PengZhiLin on 2021/8/12 15:49
*/
public class Test {
public static void main(String[] args) {
// 需求:在不改變原類,不使用繼承重寫的基礎上對LiuDeHua類的sing方法進行擴展,dace方法不擴展
// 創建LiuDeHua對象
LiuDeHua ldh = new LiuDeHua();
//ldh.sing();
//ldh.dance();
// 創建增強的LiuDeHua對象
LiuDeHuaWrapper liuDeHuaWrapper = new LiuDeHuaWrapper(ldh);
liuDeHuaWrapper.sing();
liuDeHuaWrapper.dance();
}
}
第八章 commons-io工具包
commons-io工具包的概述
commons-io是apache開源基金組織提供的一組有關IO操作的類庫,可以挺提高IO功能開發的效率。commons-io工具包提供了很多有關io操作的類,見下表:
| 包 | 功能描述 |
|---|---|
| org.apache.commons.io | 有關Streams、Readers、Writers、Files的工具類 |
| org.apache.commons.io.input | 輸入流相關的實現類,包含Reader和InputStream |
| org.apache.commons.io.output | 輸出流相關的實現類,包含Writer和OutputStream |
| org.apache.commons.io.serialization | 序列化相關的類 |
commons-io工具包的使用
步驟:
- 下載commons-io相關jar包;http://commons.apache.org/proper/commons-io/
- 把commons-io-2.7.jar包復制到指定的Module的lib目錄中
- 將commons-io-2.7.jar加入到classpath路徑中----選中jar包,右鍵add as library,確認
commons-io工具包的使用
- commons-io提供了一個工具類 org.apache.commons.io.IOUtils,封裝了大量IO讀寫操作的代碼。其中有兩個常用方法:
- public static int copy(InputStream in, OutputStream out); 把input輸入流中的內容拷貝到output輸出流中,返回拷貝的字節個數(適合文件大小為2GB以下)
- public static long copyLarge(InputStream in, OutputStream out);把input輸入流中的內容拷貝到output輸出流中,返回拷貝的字節個數(適合文件大小為2GB以上)
文件復制案例演示:
/**
* Created by PengZhiLin on 2021/8/12 16:17
*/
public class Test1_IOUtils {
public static void main(String[] args) throws Exception{
// 1.創建字節輸入流對象,關聯數據源文件路徑
FileInputStream fis = new FileInputStream("day11\\aaa\\hb.jpg");
// 2.創建字節輸出流對象,關聯目的地文件路徑
FileOutputStream fos = new FileOutputStream("day11\\ccc\\hbCopy1.jpg");
// 3.拷貝
IOUtils.copy(fis,fos);
// 4.關閉流,釋放資源
fos.close();
fis.close();
}
}
- commons-io還提供了一個工具類org.apache.commons.io.FileUtils,封裝了一些對文件操作的方法:
- public static void copyFileToDirectory(final File srcFile, final File destFile) //復制文件到另外一個目錄下。
- public static void copyDirectoryToDirectory( File file1 ,File file2 );//復制file1目錄到file2位置。
案例演示:
/**
* Created by PengZhiLin on 2021/8/12 16:20
*/
public class Test2_FileUtils {
public static void main(String[] args) throws Exception{
// 1.創建File對象,封裝數據源文件路徑
File f1 = new File("day11\\aaa\\hb.jpg");
// 2.創建File對象,封裝目的地文件夾路徑
File f2 = new File("day11\\ccc");
// 3.拷貝
FileUtils.copyFileToDirectory(f1,f2);
}
}
/**
* Created by PengZhiLin on 2021/8/12 16:20
*/
public class Test3_FileUtils {
public static void main(String[] args) throws Exception{
// 1.創建File對象,封裝數據源文件夾路徑
File f1 = new File("day11\\bbb");
// 2.創建File對象,封裝目的地文件夾路徑
File f2 = new File("day11\\ccc");
// 3.拷貝
FileUtils.copyDirectoryToDirectory(f1,f2);
}
}
總結
必須練習:
1.IO異常的處理----jdk7前,jdk7
2.屬性集-->加載配置文件數據,然后遍歷
3.字節緩沖流高效拷貝文件; 字符緩沖流恢復文本順序
4.轉換流: 轉換文件編碼的案例
5.裝飾者設計模式
6.commons-io--->拷貝文件,拷貝文件夾
- 能夠使用Properties的load方法加載文件中配置信息
public Properties() :創建一個空的屬性列表。
public void load(InputStream inStream): 從字節輸入流中讀取鍵值對。
public void load(Reader reader) 從字符輸入流中讀取鍵值對。
public Set<String> stringPropertyNames() :所有鍵的名稱的集合。
public String getProperty(String key) :使用此屬性列表中指定的鍵搜索屬性值。
public Object setProperty(String key, String value) : 保存一對屬性。
- 能夠使用字節緩沖流讀取數據到程序
BufferedInputStream: public BufferedInputStream(InputStream is);
使用InputStream中的讀數據方法
- 能夠使用字節緩沖流寫出數據到文件
BufferedOutputStream: public BufferedOutputStream(OutputStream os);
使用OutputStream中的寫數據方法
- 能夠明確字符緩沖流的作用和基本用法
BufferedReader:
public BufferedReader(Reader r);
public String readLine();
BufferedWriter:
public BufferedWriter(Writer w);
public void newLine();
- 能夠使用緩沖流的特殊功能
字節緩沖流:提高讀寫效率
字符緩沖流: 讀一行;根據系統自動寫換行分隔符
- 能夠闡述編碼表的意義
定義了字符和二進制數對應的規則
- 能夠使用轉換流讀取指定編碼的文本文件
InputStreamReader: public InputStreamReader(InputStream is,String charset)
- 能夠使用轉換流寫入指定編碼的文本文件
OutputStreamWriter: public OutputStreamWriter(OutputStream os,String charset)
- 能夠使用序列化流寫出對象到文件
ObjectOutputStream: public ObjectOutputStream(OutputStream os);
public void writeObject(Object obj);
- 能夠使用反序列化流讀取文件到程序中
ObjectInputStream: public ObjectInputStream(InputStream is);
public Object readObject();
- 能夠理解裝飾模式的實現步驟
1.裝飾類和被裝飾類需要實現同一個接口
2.裝飾類中需要接收被裝飾類的引用
3.在裝飾類中對需要擴展的方法進行擴展
4.在裝飾類中對不需要擴展的方法調用被裝飾類中同名的方法
- 能夠使用commons-io工具包
1.下載jar包
2.拷貝jar包到模塊下
3.把jar包添加到classpath路徑下
4.使用工具類調用方法
擴展-寫數據到配置文件中
-
需求: 修改配置文件中k3這個鍵對應的值為value
-
文件:
k1=v1 k2=v2 k3=v3 k4=v4 -
分析:
- 創建Properties對象
- 調用load方法加載配置文件中的鍵值對數據
- 獲取所有的鍵
- 循環遍歷所有的鍵
- 在循環中,判斷遍歷出來的鍵是否是k3,如果是就修改值為value
- 把Properties對象中所有的鍵值對寫回配置文件中
-
實現---使用Properties類的方法
-
public void store(OutputStream os,String comments) 把Properties對象中的鍵值對通過輸出流寫回配置文件中 -
public void store(Writer w,String comments) 把Properties對象中的鍵值對通過輸出流寫回配置文件中/** * Created by PengZhiLin on 2021/8/12 16:37 */ public class Test { public static void main(String[] args) throws Exception { //- 創建Properties對象 Properties pro = new Properties(); //- 調用load方法加載配置文件中的鍵值對數據 pro.load(new FileInputStream("day11\\ccc\\aa.properties")); //- 獲取所有的鍵 Set<String> keys = pro.stringPropertyNames(); //- 循環遍歷所有的鍵 for (String key : keys) { //- 在循環中,判斷遍歷出來的鍵是否是k3,如果是就修改值為value if ("k3".equals(key)){ pro.setProperty(key,"value"); } } //- 把Properties對象中所有的鍵值對寫回配置文件中 //pro.store(new FileOutputStream("day11\\ccc\\aa.properties"),"itheima"); pro.store(new FileWriter("day11\\ccc\\aa.properties"),"itheima"); } }
-
浙公網安備 33010602011771號