復(fù)習(xí)
1.字符流
FileWriter FileReader
2.ResourceBundle
3.Properties
a.都可以讀取Properties配置文件
區(qū)別:
a.ResourceBundle是靜態(tài)方法getBundle,Properties成員方法load
b.ResourceBundle一般讀取src根目錄下,Properties一般讀取項(xiàng)目根目錄下
c.ResourceBundle讀取時(shí)只需要寫文件名(不帶后綴), Properties讀取時(shí)文件名要寫全名
4.異常處理
JDK1.7之前
try{
}catch(Exception e){
}finally{
xxx.close();
}
JDK1.7以及之后
try(FileReader fr = new FileReader("1.txt")){
}catch(Exception e){
}
今日內(nèi)容
- 緩沖流(高效流, 比普通流性能更高)
- 轉(zhuǎn)換流(編碼相關(guān)的流, 指定編碼)'
- 序列化流(操作對(duì)象)
- 打印流(System.out.println())
- 設(shè)計(jì)模式(裝飾設(shè)計(jì)模式, 4個(gè)步驟)
- common-io 工具包(簡(jiǎn)化io代碼)
緩沖流
緩沖流的介紹
-
介紹
緩沖流,也叫高效流,是對(duì)4個(gè)基本的 FileXxx 流的增強(qiáng)(性能增強(qiáng), 方法基本一樣),所以也是4個(gè)流
緩沖流的基本原理,是在創(chuàng)建流對(duì)象時(shí),會(huì)創(chuàng)建一個(gè)內(nèi)置的默認(rèn)大小的緩沖區(qū)數(shù)組,通過(guò)緩沖區(qū)讀寫,減少系統(tǒng)IO次數(shù),從而提高讀寫的效率。
緩沖流的分類
-
按照數(shù)據(jù)類型分類:
緩沖字節(jié)輸入流:
BufferedInputStream---> 對(duì)普通的字節(jié)輸入流``InputStream`增強(qiáng)緩沖字節(jié)輸出流:
BufferedOutputStream---> 對(duì)普通的字節(jié)輸出流OutputStream增強(qiáng)緩沖字符輸入流:
BufferedReader---> 對(duì)普通的字符輸入流Reader增強(qiáng)緩沖字符輸出流:
BufferedWriter---> 對(duì)普通的字符輸出流Writer增強(qiáng)
字節(jié)緩沖流的介紹和使用
-
字節(jié)緩沖流的構(gòu)造
public BufferedInputStream(InputStream in):創(chuàng)建一個(gè) 新的緩沖輸入流。
public BufferedOutputStream(OutputStream out): 創(chuàng)建一個(gè)新的緩沖輸出流。 -
字節(jié)緩沖流的使用代碼
(使用一次讀取一個(gè)字節(jié)數(shù)組的方式,配合字節(jié)緩沖流使用速度更快)
public static void copy01() throws Exception{ BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("2.txt")); long start = System.currentTimeMillis(); int b = 0; while ((b = bis.read()) != -1) { bos.write(b); } long end = System.currentTimeMillis(); bis.close(); bos.close(); System.out.println(end-start); }
字符緩沖流的介紹和使用
-
字符緩沖流的構(gòu)造
public BufferedReader(Reader in):創(chuàng)建一個(gè) 新的緩沖輸入流。
public BufferedWriter(Writer out): 創(chuàng)建一個(gè)新的緩沖輸出流。 -
字符緩沖流的特有方法
BufferedRead:public String readLine(): 讀一行文字(只要沒到換行)。(讀不到會(huì)返回null)
BufferedWriter:public void newLine(): 寫一行行分隔符(換行符),由系統(tǒng)屬性定義符號(hào)(具有跨平臺(tái)性)。-
BufferedRead的一次讀取一行使用
public static void bwread() throws IOException{ BufferedReader br = new BufferedReader(new FileReader("2.txt")); System.out.println(br.readLine()); //===========一次讀取一行的標(biāo)準(zhǔn)寫法========== String line=""; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); }緩沖流練習(xí)
-
public static void main(String[] args) throws IOException {
ArrayList<String> list = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader("1.txt"));
String line ="";
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
/* Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.charAt(0)-o1.charAt(0);
}
});*/
Collections.sort(list,((o1, o2) -> o1.charAt(0)-o2.charAt(0)));
/*for (String s : list) {
System.out.println(s);
}*/
BufferedWriter bw = new BufferedWriter(new FileWriter("2"));
for (String s : list) {
bw.write(s);
bw.newLine();
}
bw.close();
}
轉(zhuǎn)換流
編碼和解碼
編碼: 把字符按照某種規(guī)則,將字符轉(zhuǎn)到字節(jié)(二進(jìn)制)存儲(chǔ)到計(jì)算機(jī)中,稱為編碼 。
解碼: 將存儲(chǔ)在計(jì)算機(jī)中的二進(jìn)制數(shù)按照某種規(guī)則解析顯示出來(lái),稱為解碼 。
字符集
字符集 Charset :也叫編碼表。是一個(gè)系統(tǒng)支持的所有字符的集合,包括各國(guó)家文字、標(biāo)點(diǎn)符號(hào)、圖形符號(hào)、數(shù)字等。
字符編碼
字符編碼 Character Encoding : 就是一套自然語(yǔ)言的字符與二進(jìn)制數(shù)之間的對(duì)應(yīng)規(guī)則。
常見的字符集和字符編碼
ASCII 字符集 --> ASCII 編碼 , 規(guī)定了ASCII字符集中所有的字符都占1個(gè)字節(jié)(0-127)用于顯示現(xiàn)代英語(yǔ),主要包括控制字符(回車鍵、退格、換行鍵等)和可顯
示字符(英文大小寫字符、阿拉伯?dāng)?shù)字和西文符號(hào))。
GBK字符集 ---> GBK編碼, 規(guī)定所有的中文字符都占2個(gè)字節(jié)(這2個(gè)字節(jié)都是負(fù)數(shù)).是為了顯示中文而設(shè)計(jì)的一套字符集。
Unicode字符集 ---> UTF-8編碼, 規(guī)定所有中文字符都占3個(gè)字節(jié),Unicode編碼系統(tǒng)為表達(dá)任意語(yǔ)言的任意字符而設(shè)計(jì),是業(yè)界的一種標(biāo)準(zhǔn),也稱為統(tǒng)一碼、標(biāo)準(zhǔn)萬(wàn)國(guó)碼。
ISO-8859-1字符集 ---> 用于顯示歐洲使用的語(yǔ)言
編碼引出的問(wèn)題
IDEA默認(rèn)使用UTF-8編碼, windows默認(rèn)使用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();
}
}
輸出結(jié)果:
???
使用轉(zhuǎn)換流InputStreamReader類解決讀取中文的問(wèn)題
轉(zhuǎn)換流 java.io.InputStreamReader ,是Reader的子類,是從字節(jié)流到字符流的橋梁。它讀取字節(jié),并使用指定的字符集將其解碼為字符。它的字符集可以由名稱指定,也可以接受平臺(tái)的默認(rèn)字符集。
-
構(gòu)造方法
InputStreamReader(InputStream in): 創(chuàng)建一個(gè)使用默認(rèn)字符集的字符流。(使用IDEA默認(rèn)編碼)
InputStreamReader(InputStream in, String charsetName): 創(chuàng)建一個(gè)指定字符集的字符流。(第二個(gè)參數(shù)為指定使用何種編碼讀取文件)
使用轉(zhuǎn)換流OutputStreamReader類寫不同編碼的中文
轉(zhuǎn)換流 java.io.OutputStreamWriter ,是Writer的子類,是從字符流到字節(jié)流的橋梁。使用指定的字符集將字符編碼為字節(jié)。它的字符集可以由名稱指定,也可以接受平臺(tái)的默認(rèn)字符集。
-
構(gòu)造方法
OutputStreamWriter(OutputStream in): 創(chuàng)建一個(gè)使用默認(rèn)字符集的字符流。
OutputStreamWriter(OutputStream in, String charsetName): 創(chuàng)建一個(gè)指定字符集的字符流。 -
按指定編碼輸出
public static void main(String[] args) throws Exception { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("1.txt"), "UTF-8"); osw.write("你好"); osw.close(); }
轉(zhuǎn)換流的理解

轉(zhuǎn)換流代碼案例
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(new FileInputStream("GBK.txt"), "GBK");
OutputStreamWriter ops = new OutputStreamWriter(new FileOutputStream("UTF-8.TXT"), "UTF-8");
int ch=0 ;
while ((ch = isr.read()) != -1) {
ops.write((char)ch);
}
isr.close();
ops.close();
}
序列化
序列化流概述
-
序列化流: 寫出對(duì)象的流
ObjectOutputStream(java.io.ObjectOutputStream 類,將Java對(duì)象的原始數(shù)據(jù)類型寫出到文件,實(shí)現(xiàn)對(duì)象的持久存儲(chǔ)。)
-
反序列化流: 讀取對(duì)象的流
ObjectInputStream(ObjectInputStream反序列化流,將之前使用ObjectOutputStream序列化的原始數(shù)據(jù)恢復(fù)為對(duì)象。)
ObjectOutputStream類的介紹和使用
-
構(gòu)造方法
public ObjectOutputStream(OutputStream out): 創(chuàng)建一個(gè)指定OutputStream的ObjectOutputStream。 -
序列化操作的前提
想要序列化, 必須將需要序列化的對(duì)象類實(shí)現(xiàn)Serializable(可序列化)接口
Serializable接口沒有需要重寫的方法, 這種接口被稱為標(biāo)記接口
-
序列化操作代碼演示
public static void main(String[] args) throws Exception{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dog.txt")); oos.writeObject(new Dog(20,"小狗狗")); oos.close(); }寫出的dog.txt文件中是字節(jié)文件.
ObjectInputStream類的介紹和使用
-
構(gòu)造方法
public ObjectInputStream(InputStream in): 創(chuàng)建一個(gè)指定InputStream的ObjectInputStream。 -
反序列化操作代碼演示
public static void main(String[] args) throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dog.txt")); Object o = ois.readObject(); System.out.println(o); ois.close(); }
反序列化可能會(huì)出現(xiàn)的異常
-
對(duì)于JVM可以反序列化對(duì)象,它必須是能夠找到class文件的類。如果找不到該類的class文件,則拋出一個(gè)
ClassNotFoundException異常。原因: 找不到序列化時(shí)的對(duì)象類
-
當(dāng)JVM反序列化對(duì)象時(shí),能找到class文件,但是class文件在序列化對(duì)象之后發(fā)生了修改,那么反序列化操作也會(huì)失敗,拋出一個(gè)
InvalidClassException異常。原因: 修改了序列化的對(duì)象類的內(nèi)容,根據(jù)版本號(hào)識(shí)別
-
Serializable 接口給需要序列化的類,提供了一個(gè)序列版本號(hào)。 serialVersionUID 該版本號(hào)的目的在于驗(yàn)證序列化的對(duì)象和對(duì)應(yīng)類是否版本匹配。(允許程序員自己管理版本號(hào)代碼如下)
public class Employee implements java.io.Serializable { // 加入序列版本號(hào) private static final long serialVersionUID = 1L; public String name; public String address; // 添加新的屬性 ,重新編譯, 可以反序列化,該屬性賦為默認(rèn)值. public int eid; public void addressCheck() { System.out.println("Address check : " + name + " -- " + address); } }
序列化多個(gè)對(duì)象
注意: 序列化流一個(gè)文件只適合序列化一個(gè)對(duì)象(如果一個(gè)文件序列化多個(gè)對(duì)象, 會(huì)缺少標(biāo)記)
-
操作步驟:
- 把序列化的多個(gè)對(duì)象,保存到一個(gè)集合對(duì)象(集合已經(jīng)實(shí)現(xiàn)了Serializable接口)
- 把這個(gè)集合作為對(duì)象,序列化到文件中(其實(shí)就是將集合容器作為對(duì)象序列化到文件中)
-
序列化多個(gè)對(duì)象代碼演示:
public class TestDemo { public static void main(String[] args) throws Exception { write(); read(); } public static void write() throws IOException { ArrayList<Dog> dogs = new ArrayList<>(); dogs.add(new Dog(23, "dahua")); dogs.add(new Dog(11, "erhua")); dogs.add(new Dog(55, "sanhua")); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dogs.txt")); oos.writeObject(dogs); oos.close(); } public static void read() throws Exception { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dogs.txt")); Object o = ois.readObject(); //反序列化文件, 返回值是Object對(duì)象, 需要強(qiáng)轉(zhuǎn)成集合(泛型用父類多態(tài)接收) for (Object dog : (ArrayList<Object>)o) { System.out.println(dog); } ois.close(); } }
打印流(PrintStream)
打印流的介紹
System.out.println()在控制臺(tái)打印輸出,是調(diào)用print 方法和 println 方法完成的,這兩個(gè)方法都來(lái)自于java.io.PrintStream 類(成為打印流),該類能夠方便地打印各種數(shù)據(jù)類型的值(打印流中重寫了各種數(shù)據(jù)類型的print和printlin方法),是一種便捷的輸出方式。
打印流的用法
-
構(gòu)造方法
public PrintStream(String fileName): 使用指定的文件名創(chuàng)建一個(gè)新的打印流。public PrintStream(File file): 直接指定file對(duì)象public PrintStream(OutputStream out): 輸出流綁定的哪個(gè)對(duì)象, 就打印到哪個(gè)對(duì)象中 -
成員方法
public void print(各種數(shù)據(jù)類型);public void println(各種數(shù)據(jù)類型); -
打印流代碼演示
public static void main(String[] args) throws Exception{ PrintStream ps1 = new PrintStream("p.txt"); PrintStream ps2 = new PrintStream(new File("p1.txt")); PrintStream ps3 = new PrintStream(new FileOutputStream("p2.txt")); ps1.print("隨便寫各種類型數(shù)據(jù)"); } -
修改系統(tǒng)打印流的流向
public static void main(String[] args) throws Exception{ PrintStream ps = new PrintStream("p.txt"); ps.print("更改打印"); System.out.println("JAVA"); //相當(dāng)于修改了System靜態(tài)變量out的值 System.setOut(ps); System.out.println(); System.out.println("java更改"); }
裝飾設(shè)計(jì)模式
設(shè)計(jì)模式是指, 前輩們?yōu)榱私鉀Q一系列問(wèn)題設(shè)計(jì)的方案
在我們今天所學(xué)的緩沖流中涉及到j(luò)ava的一種設(shè)計(jì)模式,叫做裝飾模式.
裝飾設(shè)計(jì)模式概述(作用)
指在不改變?cè)? 不適用繼承的基礎(chǔ)上, 動(dòng)態(tài)地?cái)U(kuò)展一個(gè)對(duì)象的功能.
裝飾設(shè)計(jì)模式的4個(gè)基本步驟
- 裝飾類(需要裝飾的新類)和被裝飾類(原類)必須實(shí)現(xiàn)相同的接口(可以將原類中的成員方法抽出來(lái), 放在接口中)
- 在裝飾類中必須傳入被裝飾類的引用(就是在新類中定義裝飾類的成員變量對(duì)象)
- 在裝飾類中對(duì)需要擴(kuò)展的方法進(jìn)行擴(kuò)展
- 在裝飾類中對(duì)不需要擴(kuò)展的方法調(diào)用被裝飾類中的同名方法
裝飾設(shè)計(jì)模式代碼演示
-
先提供方法接口
public interface Star { public void sing(); public void dance(); } -
讓原類去實(shí)現(xiàn)接口
public class LiuDeHua implements Star { @Override public void sing() { System.out.println("劉德華在唱忘情水..."); } @Override public void dance() { System.out.println("劉德華在跳街舞..."); } } -
寫裝飾類,在裝飾類中擴(kuò)展
/* 裝飾模式遵循原則: 裝飾類和被裝飾類必須實(shí)現(xiàn)相同的接口 在裝飾類中必須傳入被裝飾類的引用 在裝飾類中對(duì)需要擴(kuò)展的方法進(jìn)行擴(kuò)展 在裝飾類中對(duì)不需要擴(kuò)展的方法調(diào)用被裝飾類中的同名方法 */ public class LiuDeHuaWarpper implements Star { // 存放被裝飾類的引用 private LiuDeHua liuDeHua; // 通過(guò)構(gòu)造器傳入被裝飾類對(duì)象 public LiuDeHuaWarpper(LiuDeHua liuDeHua){ this.liuDeHua = liuDeHua; } @Override public void sing() { // 對(duì)需要擴(kuò)展的方法進(jìn)行擴(kuò)展增強(qiáng) System.out.println("劉德華在鳥巢的舞臺(tái)上演唱忘情水."); } @Override public void dance() { // 不需要增強(qiáng)的方法調(diào)用被裝飾類中的同名方法 liuDeHua.dance(); } }
commons-io工具包
commons-io工具包概述
commons-io是apache開源基金組織提供的一組有關(guān)IO操作的類庫(kù),可以挺提高IO功能開發(fā)的效率。commons-io工具包提供了很多有關(guān)io操作的類,見下表:
| 包 | 功能描述 |
|---|---|
| org.apache.commons.io | 有關(guān)Streams、Readers、Writers、Files的工具類 |
| org.apache.commons.io.input | 輸入流相關(guān)的實(shí)現(xiàn)類,包含Reader和InputStream |
| org.apache.commons.io.output | 輸出流相關(guān)的實(shí)現(xiàn)類,包含Writer和OutputStream |
| org.apache.commons.io.serialization | 序列化相關(guān)的類 |
commons-io工具包 使用步驟
步驟:
- 下載commons-io相關(guān)jar包;http://commons.apache.org/proper/commons-io/
- 把commons-io-2.6.jar包復(fù)制到指定的Module的lib目錄中(必須在指定的Module的lib目錄下, lib目錄和src目錄為同級(jí)目錄)
- 將commons-io-2.6.jar加入到classpath中(IDEA中右鍵該工具包選擇Add as Libary表示添加到本模塊中作為工具庫(kù))
commons-io工具包常用API
-
commons-io提供了一個(gè)工具類 org.apache.commons.io.IOUtils,封裝了大量IO讀寫操作的代碼。其中有兩個(gè)常用方法:
- public static int copy(InputStream in, OutputStream out); 把input輸入流中的內(nèi)容拷貝到output輸
出流中,返回拷貝的字節(jié)個(gè)數(shù)(適合文件大小為2GB以下) - public static long copyLarge(InputStream in, OutputStream out);把input輸入流中的內(nèi)容拷貝到
output輸出流中,返回拷貝的字節(jié)個(gè)數(shù)(適合文件大小為2GB以上)
代碼演示
public static void main(String[] args) throws Exception { // 文件路徑需要修改,改成自己文件的路徑 File file = new File("src/test.txt"); FileInputStream is = new FileInputStream(file); // 文件路徑需要修改 File file1 = new File("src/test1.txt"); FileOutputStream os = new FileOutputStream(file1); // 文件復(fù)制 IOUtils.copy(is, os); } - public static int copy(InputStream in, OutputStream out); 把input輸入流中的內(nèi)容拷貝到output輸
-
commons-io還提供了一個(gè)工具類org.apache.commons.io.FileUtils,封裝了一些對(duì)文件操作的方法:
- public static void copyFileToDirectory(?nal File srcFile, ?nal File destFile) //復(fù)制文件到另外一個(gè)目錄
下。 - public static void copyDirectoryToDirectory( ?le1 , ?le2 );//復(fù)制?le1目錄到?le2位置。
代碼演示
public static void main(String[] args) throws IOException { //1.將d:\\視頻.itcast文件復(fù)制到e:\\下 FileUtils.copyFileToDirectory(new File("d:\\視頻.itcast"), new File("e:\\")); //2.將"d:\\多級(jí)目錄"復(fù)制到"e:\\"下。 FileUtils.copyDirectoryToDirectory(new File("d:\\多級(jí)目錄"), new File("e:\\")); } - public static void copyFileToDirectory(?nal File srcFile, ?nal File destFile) //復(fù)制文件到另外一個(gè)目錄
今日小結(jié)
1.緩沖流【重點(diǎn)】
字節(jié)緩沖流(BufferedOutputStream和BufferedInputStream),沒有特有方法,性能比普通流更高字符緩沖流(BufferedWriter和BufferedReader),有特有方法,性能比普通流更高 BufferedWriter: public void newLine(); BufferedReader: public String readLine();2.轉(zhuǎn)換流【重點(diǎn)】
轉(zhuǎn)換輸出流: 可以指定編碼寫文件
OutputStreamWriter
public OutputStreamWriter(OutputStream out,String 指定的編碼);
轉(zhuǎn)換輸入流: 可以指定編碼讀文件
InputStreamReader
public InputStreamReader(InputStream in,String 指定的編碼);3.序列化流【理解】
序列化流: 寫對(duì)象
ObjectOutputStream
public void writeObject(對(duì)象);//該對(duì)象的類必須實(shí)現(xiàn)java.io.Serializable接口
反序列化流: 讀對(duì)象
ObjectInputStream
public Object readObject();
4.打印流【理解】
PrintStream ps = new PrintStream(String path/File file/OutputStream out);
方法:
print(各種數(shù)據(jù)類型);
println(各種數(shù)據(jù)類型);5.裝飾設(shè)計(jì)模式【理解】
步驟:
a.被裝飾類和裝飾類實(shí)現(xiàn)同一個(gè)接口
b.裝飾類內(nèi)部必須含有被裝飾類的引用
c.在裝飾類中對(duì)需要裝飾的方法進(jìn)行裝飾
d.在裝飾類中對(duì)不需要裝飾的方法調(diào)用原對(duì)象的方法6.commons-io【重點(diǎn)】
IOUtils 復(fù)制文件(2G以上和2G以下)
FileUtils 復(fù)制文件和復(fù)制文件夾