1. 緩沖流
昨天學習了基本的一些流,作為IO流的入門,今天我們要見識一些更強大的流。比如能夠高效讀寫的緩沖流,能夠轉換編碼的轉換流,能夠持久化存儲對象的序列化流等等。這些功能更為強大的流,都是在基本的流對象基礎之上創建而來的,就像穿上鎧甲的武士一樣,相當于是對基本流對象的一種增強。
1.1 概述
緩沖流,也叫高效流,是對4個基本的FileXxx
流的增強,所以也是4個流,按照數據類型分類:
- 字節緩沖流:
BufferedInputStream
,BufferedOutputStream
- 字符緩沖流:
BufferedReader
,BufferedWriter
緩沖流的基本原理,是在創建流對象時,會創建一個內置的默認大小的緩沖區數組,通過緩沖區讀寫,減少系統IO次數,從而提高讀寫的效率。
1.2 字節緩沖流
構造方法
public BufferedInputStream(InputStream in)
:創建一個 新的緩沖輸入流。public BufferedOutputStream(OutputStream out)
: 創建一個新的緩沖輸出流。
構造舉例,代碼如下:
// 創建字節緩沖輸入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 創建字節緩沖輸出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
效率測試
查詢API,緩沖流讀寫方法與基本的流是一致的,我們通過復制大文件(375MB),測試它的效率。
- 基本流,代碼如下:
public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (FileInputStream fis = new FileInputStream("jdk9.exe");FileOutputStream fos = new FileOutputStream("copy.exe")){// 讀寫數據int b;while ((b = fis.read()) != -1) {fos.write(b);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("普通流復制時間:"+(end - start)+" 毫秒");}
}十幾分鐘過去了...
- 緩沖流,代碼如下:
public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));){// 讀寫數據int b;while ((b = bis.read()) != -1) {bos.write(b);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("緩沖流復制時間:"+(end - start)+" 毫秒");}
}緩沖流復制時間:8016 毫秒
如何更快呢?
使用數組的方式,代碼如下:
public class BufferedDemo {public static void main(String[] args) throws FileNotFoundException {// 記錄開始時間long start = System.currentTimeMillis();// 創建流對象try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("jdk9.exe"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.exe"));){// 讀寫數據int len;byte[] bytes = new byte[8*1024];while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0 , len);}} catch (IOException e) {e.printStackTrace();}// 記錄結束時間long end = System.currentTimeMillis();System.out.println("緩沖流使用數組復制時間:"+(end - start)+" 毫秒");}
}
緩沖流使用數組復制時間:666 毫秒
1.3 字符緩沖流
構造方法
public BufferedReader(Reader in)
:創建一個 新的緩沖輸入流。public BufferedWriter(Writer out)
: 創建一個新的緩沖輸出流。
構造舉例,代碼如下:
// 創建字符緩沖輸入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 創建字符緩沖輸出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
特有方法
字符緩沖流的基本方法與普通字符流調用方式一致,不再闡述,我們來看它們具備的特有方法。
- BufferedReader:
public String readLine()
: 讀一行文字。 - BufferedWriter:
public void newLine()
: 寫一行行分隔符,由系統屬性定義符號。
readLine
方法演示,代碼如下:
public class BufferedReaderDemo {public static void main(String[] args) throws IOException {// 創建流對象BufferedReader br = new BufferedReader(new FileReader("in.txt"));// 定義字符串,保存讀取的一行文字String line = null;// 循環讀取,讀取到最后返回nullwhile ((line = br.readLine())!=null) {System.out.print(line);System.out.println("------");}// 釋放資源br.close();}
}
newLine
方法演示,代碼如下:
public class BufferedWriterDemo throws IOException {public static void main(String[] args) throws IOException {// 創建流對象BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));// 寫出數據bw.write("黑馬");// 寫出換行bw.newLine();bw.write("程序");bw.newLine();bw.write("員");bw.newLine();// 釋放資源bw.close();}
}
輸出效果:
黑馬
程序
員
1.4 練習:文本排序
請將文本信息恢復順序。
3.侍中、侍郎郭攸之、費祎、董允等,此皆良實,志慮忠純,是以先帝簡拔以遺陛下。愚以為宮中之事,事無大小,悉以咨之,然后施行,必得裨補闕漏,有所廣益。
8.愿陛下托臣以討賊興復之效,不效,則治臣之罪,以告先帝之靈。若無興德之言,則責攸之、祎、允等之慢,以彰其咎;陛下亦宜自謀,以咨諏善道,察納雅言,深追先帝遺詔,臣不勝受恩感激。
4.將軍向寵,性行淑均,曉暢軍事,試用之于昔日,先帝稱之曰能,是以眾議舉寵為督。愚以為營中之事,悉以咨之,必能使行陣和睦,優劣得所。
2.宮中府中,俱為一體,陟罰臧否,不宜異同。若有作奸犯科及為忠善者,宜付有司論其刑賞,以昭陛下平明之理,不宜偏私,使內外異法也。
1.先帝創業未半而中道崩殂,今天下三分,益州疲弊,此誠危急存亡之秋也。然侍衛之臣不懈于內,忠志之士忘身于外者,蓋追先帝之殊遇,欲報之于陛下也。誠宜開張圣聽,以光先帝遺德,恢弘志士之氣,不宜妄自菲薄,引喻失義,以塞忠諫之路也。
9.今當遠離,臨表涕零,不知所言。
6.臣本布衣,躬耕于南陽,茍全性命于亂世,不求聞達于諸侯。先帝不以臣卑鄙,猥自枉屈,三顧臣于草廬之中,咨臣以當世之事,由是感激,遂許先帝以驅馳。后值傾覆,受任于敗軍之際,奉命于危難之間,爾來二十有一年矣。
7.先帝知臣謹慎,故臨崩寄臣以大事也。受命以來,夙夜憂嘆,恐付托不效,以傷先帝之明,故五月渡瀘,深入不毛。今南方已定,兵甲已足,當獎率三軍,北定中原,庶竭駑鈍,攘除奸兇,興復漢室,還于舊都。此臣所以報先帝而忠陛下之職分也。至于斟酌損益,進盡忠言,則攸之、祎、允之任也。
5.親賢臣,遠小人,此先漢所以興隆也;親小人,遠賢臣,此后漢所以傾頹也。先帝在時,每與臣論此事,未嘗不嘆息痛恨于桓、靈也。侍中、尚書、長史、參軍,此悉貞良死節之臣,愿陛下親之信之,則漢室之隆,可計日而待也。
案例分析
- 逐行讀取文本信息。
- 把讀取到的文本存儲到集合中
- 對集合中的文本進行排序
- 遍歷集合,按順序,寫出文本信息。
案例實現
public class Demo05Test {public static void main(String[] args) throws IOException {//1.創建ArrayList集合,泛型使用StringArrayList<String> list = new ArrayList<>();//2.創建BufferedReader對象,構造方法中傳遞FileReader對象BufferedReader br = new BufferedReader(new FileReader("10_IO\\in.txt"));//3.創建BufferedWriter對象,構造方法中傳遞FileWriter對象BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\out.txt"));//4.使用BufferedReader對象中的方法readLine,以行的方式讀取文本String line;while((line = br.readLine())!=null){//5.把讀取到的文本存儲到ArrayList集合中list.add(line);}//6.使用Collections集合工具類中的方法sort,對集合中的元素按照自定義規則排序Collections.sort(list, new Comparator<String>() {/*o1-o2:升序o2-o1:降序*/@Overridepublic int compare(String o1, String o2) {//依次比較集合中兩個元素的首字母,升序排序return o1.charAt(0)-o2.charAt(0);}});//7.遍歷ArrayList集合,獲取每一個元素for (String s : list) {//8.使用BufferedWriter對象中的方法wirte,把遍歷得到的元素寫入到文本中(內存緩沖區中)bw.write(s);//9.寫換行bw.newLine();}//10.釋放資源bw.close();br.close();}
}
2. 轉換流
2.1 字符編碼和字符集
字符編碼
計算機中儲存的信息都是用二進制數表示的,而我們在屏幕上看到的數字、英文、標點符號、漢字等字符是二進制數轉換之后的結果。按照某種規則,將字符存儲到計算機中,稱為編碼 。反之,將存儲在計算機中的二進制數按照某種規則解析顯示出來,稱為解碼 。比如說,按照A規則存儲,同樣按照A規則解析,那么就能顯示正確的文本符號。反之,按照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-8859-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輔助字符,使用四字節編碼。
2.2 編碼引出的問題
在IDEA中,使用FileReader
讀取項目中的文本文件。由于IDEA的設置,都是默認的UTF-8
編碼,所以沒有任何問題。但是,當讀取Windows系統中創建的文本文件時,由于Windows系統的默認是GBK編碼,就會出現亂碼。
public class ReaderDemo {public static void main(String[] args) throws IOException {FileReader fileReader = new FileReader("E:\\File_GBK.txt");int read;while ((read = fileReader.read()) != -1) {System.out.print((char)read);}fileReader.close();}
}
輸出結果:
���
那么如何讀取GBK編碼的文件呢?
2.3 InputStreamReader類
轉換流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 ReaderDemo2 {public static void main(String[] args) throws IOException {// 定義文件路徑,文件為gbk編碼String FileName = "E:\\file_gbk.txt";// 創建流對象,默認UTF8編碼InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));// 創建流對象,指定GBK編碼InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");// 定義變量,保存字符int read;// 使用默認編碼字符流讀取,亂碼while ((read = isr.read()) != -1) {System.out.print((char)read); // ��?�}isr.close();// 使用指定編碼字符流讀取,正常解析while ((read = isr2.read()) != -1) {System.out.print((char)read);// 大家好}isr2.close();}
}
2.4 OutputStreamWriter類
轉換流java.io.OutputStreamWriter
,是Writer的子類,是從字符流到字節流的橋梁。使用指定的字符集將字符編碼為字節。它的字符集可以由名稱指定,也可以接受平臺的默認字符集。
構造方法
OutputStreamWriter(OutputStream in)
: 創建一個使用默認字符集的字符流。OutputStreamWriter(OutputStream in, String charsetName)
: 創建一個指定字符集的字符流。
構造舉例,代碼如下:
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");
指定編碼寫出
public class OutputDemo {public static void main(String[] args) throws IOException {// 定義文件路徑String FileName = "E:\\out.txt";// 創建流對象,默認UTF8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));// 寫出數據osw.write("你好"); // 保存為6個字節osw.close();// 定義文件路徑String FileName2 = "E:\\out2.txt";// 創建流對象,指定GBK編碼OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");// 寫出數據osw2.write("你好");// 保存為4個字節osw2.close();}
}
轉換流理解圖解
轉換流是字節與字符間的橋梁!
2.5 練習:轉換文件編碼
將GBK編碼的文本文件,轉換為UTF-8編碼的文本文件。
案例分析
- 指定GBK編碼的轉換流,讀取文本文件。
- 使用UTF-8編碼的轉換流,寫出文本文件。
案例實現
public class TransDemo {public static void main(String[] args) { // 1.定義文件路徑String srcFile = "file_gbk.txt";String destFile = "file_utf8.txt";// 2.創建流對象// 2.1 轉換輸入流,指定GBK編碼InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");// 2.2 轉換輸出流,默認utf8編碼OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));// 3.讀寫數據// 3.1 定義數組char[] cbuf = new char[1024];// 3.2 定義長度int len;// 3.3 循環讀取while ((len = isr.read(cbuf))!=-1) {// 循環寫出osw.write(cbuf,0,len);}// 4.釋放資源osw.close();isr.close();}
}
3. 序列化
3.1 概述
Java 提供了一種對象序列化的機制。用一個字節序列可以表示一個對象,該字節序列包含該對象的數據
、對象的類型
和對象中存儲的屬性
等信息。字節序列寫出到文件之后,相當于文件中持久保存了一個對象的信息。
反之,該字節序列還可以從文件中讀取回來,重構對象,對它進行反序列化。對象的數據
、對象的類型
和對象中存儲的數據
信息,都可以用來在內存中創建對象。看圖理解序列化:
3.2 ObjectOutputStream類
java.io.ObjectOutputStream
類,將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 SerializeDemo{public static void main(String [] args) {Employee e = new Employee();e.name = "zhangsan";e.address = "beiqinglu";e.age = 20; try {// 創建序列化流對象ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));// 寫出對象out.writeObject(e);// 釋放資源out.close();fileOut.close();System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年齡沒有被序列化。} catch(IOException i) {i.printStackTrace();}}
}
輸出結果:
Serialized data is saved
3.3 ObjectInputStream類
ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數據恢復為對象。
構造方法
public ObjectInputStream(InputStream in)
: 創建一個指定InputStream的ObjectInputStream。
反序列化操作1
如果能找到一個對象的class文件,我們可以進行反序列化操作,調用ObjectInputStream
讀取對象的方法:
public final Object readObject ()
: 讀取一個對象。
public class DeserializeDemo {public static void main(String [] args) {Employee e = null;try { // 創建反序列化流FileInputStream fileIn = new FileInputStream("employee.txt");ObjectInputStream in = new ObjectInputStream(fileIn);// 讀取一個對象e = (Employee) in.readObject();// 釋放資源in.close();fileIn.close();}catch(IOException i) {// 捕獲其他異常i.printStackTrace();return;}catch(ClassNotFoundException c) {// 捕獲類找不到異常System.out.println("Employee class not found");c.printStackTrace();return;}// 無異常,直接打印輸出System.out.println("Name: " + e.name); // zhangsanSystem.out.println("Address: " + e.address); // beiqingluSystem.out.println("age: " + e.age); // 0}
}
對于JVM可以反序列化對象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個 ClassNotFoundException
異常。
反序列化操作2
**另外,當JVM反序列化對象時,能找到class文件,但是class文件在序列化對象之后發生了修改,那么反序列化操作也會失敗,拋出一個InvalidClassException
異常。**發生這個異常的原因如下:
- 該類的序列版本號與從流中讀取的類描述符的版本號不匹配
- 該類包含未知數據類型
- 該類沒有可訪問的無參數構造方法
Serializable
接口給需要序列化的類,提供了一個序列版本號。serialVersionUID
該版本號的目的在于驗證序列化的對象和對應類是否版本匹配。
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);}
}
3.4 練習:序列化集合
- 將存有多個自定義對象的集合序列化操作,保存到
list.txt
文件中。 - 反序列化
list.txt
,并遍歷集合,打印對象信息。
案例分析
- 把若干學生對象 ,保存到集合中。
- 把集合序列化。
- 反序列化讀取時,只需要讀取一次,轉換為集合類型。
- 遍歷集合,可以打印所有的學生信息
案例實現
public class SerTest {public static void main(String[] args) throws Exception {// 創建 學生對象Student student = new Student("老王", "laow");Student student2 = new Student("老張", "laoz");Student student3 = new Student("老李", "laol");ArrayList<Student> arrayList = new ArrayList<>();arrayList.add(student);arrayList.add(student2);arrayList.add(student3);// 序列化操作// serializ(arrayList);// 反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));// 讀取對象,強轉為ArrayList類型ArrayList<Student> list = (ArrayList<Student>)ois.readObject();for (int i = 0; i < list.size(); i++ ){Student s = list.get(i);System.out.println(s.getName()+"--"+ s.getPwd());}}private static void serializ(ArrayList<Student> arrayList) throws Exception {// 創建 序列化流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("list.txt"));// 寫出對象oos.writeObject(arrayList);// 釋放資源oos.close();}
}
4. 打印流
4.1 概述
平時我們在控制臺打印輸出,是調用print
方法和println
方法完成的,這兩個方法都來自于java.io.PrintStream
類,該類能夠方便地打印各種數據類型的值,是一種便捷的輸出方式。
4.2 PrintStream類
構造方法
public PrintStream(String fileName)
: 使用指定的文件名創建一個新的打印流。
構造舉例,代碼如下:
PrintStream ps = new PrintStream("ps.txt");
改變打印流向
System.out
就是PrintStream
類型的,只不過它的流向是系統規定的,打印在控制臺上。不過,既然是流對象,我們就可以玩一個"小把戲",改變它的流向。
public class PrintDemo {public static void main(String[] args) throws IOException {// 調用系統的打印流,控制臺直接輸出97System.out.println(97);// 創建打印流,指定文件的名稱PrintStream ps = new PrintStream("ps.txt");// 設置系統的打印流流向,輸出到ps.txtSystem.setOut(ps);// 調用系統的打印流,ps.txt中輸出97System.out.println(97);}
}
5. 壓縮流和解壓縮流
壓縮流:
? 負責壓縮文件或者文件夾
解壓縮流:
? 負責把壓縮包中的文件和文件夾解壓出來
/*
* 解壓縮流
*
* */
public class ZipStreamDemo1 {public static void main(String[] args) throws IOException {//1.創建一個File表示要解壓的壓縮包File src = new File("D:\\aaa.zip");//2.創建一個File表示解壓的目的地File dest = new File("D:\\");//調用方法unzip(src,dest);}//定義一個方法用來解壓public static void unzip(File src,File dest) throws IOException {//解壓的本質:把壓縮包里面的每一個文件或者文件夾讀取出來,按照層級拷貝到目的地當中//創建一個解壓縮流用來讀取壓縮包中的數據ZipInputStream zip = new ZipInputStream(new FileInputStream(src));//要先獲取到壓縮包里面的每一個zipentry對象//表示當前在壓縮包中獲取到的文件或者文件夾ZipEntry entry;while((entry = zip.getNextEntry()) != null){System.out.println(entry);if(entry.isDirectory()){//文件夾:需要在目的地dest處創建一個同樣的文件夾File file = new File(dest,entry.toString());file.mkdirs();}else{//文件:需要讀取到壓縮包中的文件,并把他存放到目的地dest文件夾中(按照層級目錄進行存放)FileOutputStream fos = new FileOutputStream(new File(dest,entry.toString()));int b;while((b = zip.read()) != -1){//寫到目的地fos.write(b);}fos.close();//表示在壓縮包中的一個文件處理完畢了。zip.closeEntry();}}zip.close();}
}
public class ZipStreamDemo2 {public static void main(String[] args) throws IOException {/** 壓縮流* 需求:* 把D:\\a.txt打包成一個壓縮包* *///1.創建File對象表示要壓縮的文件File src = new File("D:\\a.txt");//2.創建File對象表示壓縮包的位置File dest = new File("D:\\");//3.調用方法用來壓縮toZip(src,dest);}/** 作用:壓縮* 參數一:表示要壓縮的文件* 參數二:表示壓縮包的位置* */public static void toZip(File src,File dest) throws IOException {//1.創建壓縮流關聯壓縮包ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));//2.創建ZipEntry對象,表示壓縮包里面的每一個文件和文件夾//參數:壓縮包里面的路徑ZipEntry entry = new ZipEntry("aaa\\bbb\\a.txt");//3.把ZipEntry對象放到壓縮包當中zos.putNextEntry(entry);//4.把src文件中的數據寫到壓縮包當中FileInputStream fis = new FileInputStream(src);int b;while((b = fis.read()) != -1){zos.write(b);}zos.closeEntry();zos.close();}
}
public class ZipStreamDemo3 {public static void main(String[] args) throws IOException {/** 壓縮流* 需求:* 把D:\\aaa文件夾壓縮成一個壓縮包* *///1.創建File對象表示要壓縮的文件夾File src = new File("D:\\aaa");//2.創建File對象表示壓縮包放在哪里(壓縮包的父級路徑)File destParent = src.getParentFile();//D:\\//3.創建File對象表示壓縮包的路徑File dest = new File(destParent,src.getName() + ".zip");//4.創建壓縮流關聯壓縮包ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));//5.獲取src里面的每一個文件,變成ZipEntry對象,放入到壓縮包當中toZip(src,zos,src.getName());//aaa//6.釋放資源zos.close();}/** 作用:獲取src里面的每一個文件,變成ZipEntry對象,放入到壓縮包當中* 參數一:數據源* 參數二:壓縮流* 參數三:壓縮包內部的路徑* */public static void toZip(File src,ZipOutputStream zos,String name) throws IOException {//1.進入src文件夾File[] files = src.listFiles();//2.遍歷數組for (File file : files) {if(file.isFile()){//3.判斷-文件,變成ZipEntry對象,放入到壓縮包當中ZipEntry entry = new ZipEntry(name + "\\" + file.getName());//aaa\\no1\\a.txtzos.putNextEntry(entry);//讀取文件中的數據,寫到壓縮包FileInputStream fis = new FileInputStream(file);int b;while((b = fis.read()) != -1){zos.write(b);}fis.close();zos.closeEntry();}else{//4.判斷-文件夾,遞歸toZip(file,zos,name + "\\" + file.getName());// no1 aaa \\ no1}}}
}
6. 工具包(Commons-io)
介紹:
? Commons是apache開源基金組織提供的工具包,里面有很多幫助我們提高開發效率的API
比如:
? StringUtils 字符串工具類
? NumberUtils 數字工具類
? ArrayUtils 數組工具類
? RandomUtils 隨機數工具類
? DateUtils 日期工具類
? StopWatch 秒表工具類
? ClassUtils 反射工具類
? SystemUtils 系統工具類
? MapUtils 集合工具類
? Beanutils bean工具類
? Commons-io io的工具類
? 等等…
其中:Commons-io是apache開源基金組織提供的一組有關IO操作的開源工具包。
作用:提高IO流的開發效率。
使用方式:
1,新建lib文件夾
2,把第三方jar包粘貼到文件夾中
3,右鍵點擊add as a library
代碼示例:
public class CommonsIODemo1 {public static void main(String[] args) throws IOException {/*FileUtils類static void copyFile(File srcFile, File destFile) 復制文件static void copyDirectory(File srcDir, File destDir) 復制文件夾static void copyDirectoryToDirectory(File srcDir, File destDir) 復制文件夾static void deleteDirectory(File directory) 刪除文件夾static void cleanDirectory(File directory) 清空文件夾static String readFileToString(File file, Charset encoding) 讀取文件中的數據變成成字符串static void write(File file, CharSequence data, String encoding) 寫出數據IOUtils類public static int copy(InputStream input, OutputStream output) 復制文件public static int copyLarge(Reader input, Writer output) 復制大文件public static String readLines(Reader input) 讀取數據public static void write(String data, OutputStream output) 寫出數據*//* File src = new File("myio\\a.txt");File dest = new File("myio\\copy.txt");FileUtils.copyFile(src,dest);*//*File src = new File("D:\\aaa");File dest = new File("D:\\bbb");FileUtils.copyDirectoryToDirectory(src,dest);*//*File src = new File("D:\\bbb");FileUtils.cleanDirectory(src);*/}
}
7. 工具包(hutool)
介紹:
? Commons是國人開發的開源工具包,里面有很多幫助我們提高開發效率的API
比如:
? DateUtil 日期時間工具類
? TimeInterval 計時器工具類
? StrUtil 字符串工具類
? HexUtil 16進制工具類
? HashUtil Hash算法類
? ObjectUtil 對象工具類
? ReflectUtil 反射工具類
? TypeUtil 泛型類型工具類
? PageUtil 分頁工具類
? NumberUtil 數字工具類
使用方式:
1,新建lib文件夾
2,把第三方jar包粘貼到文件夾中
3,右鍵點擊add as a library
代碼示例:
public class Test1 {public static void main(String[] args) {/*FileUtil類:file:根據參數創建一個file對象touch:根據參數創建文件writeLines:把集合中的數據寫出到文件中,覆蓋模式。appendLines:把集合中的數據寫出到文件中,續寫模式。readLines:指定字符編碼,把文件中的數據,讀到集合中。readUtf8Lines:按照UTF-8的形式,把文件中的數據,讀到集合中copy:拷貝文件或者文件夾*//* File file1 = FileUtil.file("D:\\", "aaa", "bbb", "a.txt");System.out.println(file1);//D:\aaa\bbb\a.txtFile touch = FileUtil.touch(file1);System.out.println(touch);ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("aaa");list.add("aaa");File file2 = FileUtil.writeLines(list, "D:\\a.txt", "UTF-8");System.out.println(file2);*//* ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("aaa");list.add("aaa");File file3 = FileUtil.appendLines(list, "D:\\a.txt", "UTF-8");System.out.println(file3);*/List<String> list = FileUtil.readLines("D:\\a.txt", "UTF-8");System.out.println(list);}
}