IO流大本营
第一節 轉換流
1.作用:
?? ?a.實現字節流到字符流的轉換
?? ?b.解決中文亂碼的問題
2.中文編碼
?? ?GB2312 ? (采用兩個字節保存字符漢字,英文數字一個字節)
?? ?GBK ? ?(采用兩個字節保存字符漢字,英文數字一個字節)
?? ?GB18030 ? (英文數字都是一個字節,中文是兩個或四個字節)
? ? ANSI ? ?在簡體中文Windows操作系統中, ANSI 編碼代表 GBK 編碼
? ? Big5 ? ?繁體中文
? ? ISO-8859-1 ? ?收錄除ASCII外,還包括西歐,希臘語,泰語,阿拉伯語,希伯來語對應的文字符號
3.Unicode字符集(包含每個國家的所有字符)國際通用
?? ?unicode編碼 ?使用兩個字節---65536個字符,浪費空間
?? ?為了節省空間使用轉碼形式
?? ?utf-8 ? ? 使用 1 、2、3個字節(EF BB BF:記事本添加的BOM(Byte Order Mark)頭,編碼的標記)
?? ?utf-16 ? ?使用兩個字節---65536個字符(FF FE 小端(尾) FE FF 大端(尾))
?? ?utf-32 ? ?使用4個字節
4.只有轉換流才能指定讀取和寫入的字符集
1.1 InputStreamReader類
InputStreamReader:把外部設備的二進制字節流轉換成字符流讀取到內存,并指定編碼
代碼實現:
public class InputStreamReaderDemo {public static void main(String[] args) throws IOException {//1.實例化File的對象//File file = new File("file/input1.txt");//2.實例化轉換輸入流的對象//注意:當一個流的存在的意義是為了實例化另外一個流,則這個流不需要手動進行關閉//InputStream input = new FileInputStream(file);//InputStreamReader reader = new InputStreamReader(input);//使用默認的字符集【GBK】進行實例化轉換流//InputStreamReader reader = new InputStreamReader(new FileInputStream(new File("file/input1.txt")));//使用指定字符集進行實例化轉換流//字符集一般使用字符串直接傳參,不區分大小寫,但是,如果字符集書寫有誤的話,則會跑出java.io.UnsupportedEncodingExceptionInputStreamReader reader = new InputStreamReader(new FileInputStream(new File("file/input1.txt")),"UTF-8");//3.讀取char[] arr = new char[16];int len = 0; while((len = reader.read(arr)) != -1) {String string = new String(arr, 0, len);System.out.println(string);}reader.close();} }1.2 OutputStreamWriter類
OutputStreamWriter:把內存中的字符使用指定的編碼,轉換成二進制字節流存儲到外部設備代碼實現:
public class OutputStreamWriterDemo {public static void main(String[] args) throws IOException {//需求:將一段文本以utf-8的格式寫入到文件中【注,文件格式為默認格式】//1.實例化FIle對象//注意:對于所有的輸出流而言,文件可以不存在,在進行寫入的過程中可以自動進行創建//但是,對于所有的輸入流而言,文件必須先存在,然后才能操作,否則,會拋FileNotFounedExceptionFile file = new File("file/output1.txt");//2.實例化轉換輸出流//如果不想覆蓋源文件中的內容時,則在傳參的時候,設置一個參數為trueOutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file,true), "utf-8"); ?//3.寫入writer.write("客戶放假,剛回家");//4.刷新writer.flush();//5.關閉writer.close();} }?
第二節 緩沖流
作用:主要是為了增強基礎流的功能,提高流的讀寫效率,減少訪問磁盤的次數 ? 注意:如果使用記事本創建的文件,文件是utf-8或者unicode編碼,文件的前面有一個BOM(Byte Order Mark)頭,BOM頭作用是指定文件使用的編碼類型。GBK編碼沒有添加bom頭。 utf-8:EF BB BF unicode 小端: FF FE ? ? 66 00 unicode 大端 :FE FF ? ?00 662.1 BufferedInputStream類
public class BufferedInputStreamDemo {public static void main(String[] args) throws IOException {//1.實例化一個File對象File file = new File("file/test22.txt"); //2.實例化一個緩沖字節輸入流的對象BufferedInputStream input = new BufferedInputStream(new FileInputStream(file)); //3.讀取byte[] arr = new byte[1024];int len = 0;while((len = input.read(arr)) != -1) {String string = new String(arr, 0, len);}} }2.2 BufferedOutputStream類
BufferedOutputStream內部默認的緩存大小是8KB,每次寫入時存儲到緩存中的byte數組中,當數組存滿時,會把數組中的數據寫入文件,并且緩存下標歸零。 public class BufferedOutputStreamDemo {public static void main(String[] args) throws IOException {//實例化FIle對象File file = new File("test33.txt"); //實例化換種字節輸出流 BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file)); //寫output.write("你好hello".getBytes()); //刷新output.flush(); //關閉output.close();} }2.3 BufferedReader類
public class BufferedReaderDemo {public static void main(String[] args) throws IOException {//1.實例化FIle對象File file = new File("test33.txt"); //2.實例化緩沖字符流的對象BufferedReader reader = new BufferedReader(new FileReader(file)); //方式一:read循環讀取char[] arr = new char[8];int len = 0;while((len = reader.read(arr)) != -1) {String string = new String(arr, 0, len);}//方式二:readLine循環讀取String result = null;while((result = reader.readLine()) != null) {System.out.println("第一行:" + result);} reader.close();} }2.4 BufferedWriter類
public class BufferedWriterDemo {public static void main(String[] args) throws IOException {// 實例化FIle對象File file = new File("test33.txt");// 實例化緩沖字符輸出流BufferedWriter writer = new BufferedWriter(new FileWriter(file,true));// 寫writer.write("今天天氣還可以");// 作用:主要就是為了換行writer.newLine();// 刷新writer.flush();// 關閉writer.close();} }?
第三節 內存流
3.1ByteArrayIn(Out)putStream類
輸入和輸出都是從文件中來的,當然,也可將輸出輸入的位置設置在內存上,這就需要ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream:將內容寫入到內存中,是Inputstream的子類
ByteArrayOutputStream:將內存中數據輸出,是OutputStream的子類
注:此時的操作應該以內存為操作點 ? ?
注意:內存操作流的操作對象,一定是以內存為主準,不要以硬盤為準。
案例:完成一個字母大小寫轉換的程序
public class TextDemo02 {public static void main(String[] args) throws IOException {//定義一個字符串,全部由大寫字母組成String string = "HELLOWORLD";//1.內存輸入流//向內存中輸出內容,注意:跟文件讀取不一樣,不設置文件路徑ByteArrayInputStream bis ?= new ByteArrayInputStream(string.getBytes());//2.內存輸出流//準備從內存中讀取內容,注意:跟文件讀取不一樣,不設置文件路徑ByteArrayOutputStream bos = new ByteArrayOutputStream();int temp = 0;//3.read()方法每次只讀取一個字符while((temp = bis.read()) != -1) {//將讀取的數字轉為字符char c = (char)temp;//將字符變為大寫bos.write(Character.toLowerCase(c));}//循環結束之后,所有的數據都在ByteArrayOutputStream中//取出內容,將緩沖區內容轉換為字符串String newString = bos.toString();//4.關閉流bis.close();bos.close();System.out.println(newString);} } ?第四節 標準輸入輸出流
4.1PrintStream和PrintWriter
Java的標準輸入/輸出分別通過System.in和System.out實現,默認情況下分別代表是鍵盤和顯示器
PrintStream類:PrintStream為其他輸出流添加了功能,使它們能夠方便地打印各種數據值表示形式。
PrintWriter類:向文本輸出流打印對象的格式化表示形式。此類實現在 PrintStream中的所有 print方法。它不包含用于寫入原始字節的方法。
代碼實現:
public static void main(String[] args)throws Exception {//1創建PrintStream//PrintStream ps=new PrintStream("d:\\print.txt");PrintWriter pw=new PrintWriter("d:\\print.txt");//2打印pw.println(true);pw.println(3.14);pw.println(100);pw.println("我愛北京");//3刷新pw.flush();//4關閉pw.close(); }public class PrintStreamDemo {public static void main(String[] args) throws FileNotFoundException {//System.out.println("hello world");//創建打印流的對象//注意:默認打印到控制臺,但是,如果采用setOut方法進行重定向之后,將輸出到指定的文件中PrintStream print = new PrintStream(new FileOutputStream(new File("test33.txt")));static void setErr(PrintStream err) //重新分配“標準”錯誤輸出流。 static void setIn(InputStream in) //重新分配“標準”輸入流。 static void setOut(PrintStream out) //重新分配“標準”輸出流。 //將標準輸出重定向到print的輸出流System.setOut(print);System.out.println("hello world");} } public class InputStreamDemo {public static void main(String[] args) throws FileNotFoundException {//重新初始化System.outPrintStream ps = new PrintStream("Taylor.txt");System.setOut(ps);//輸出重定向,輸出到Taylor.txt文件中for (int i = 0; i < 5; i++) {System.out.println("好久不見,Taylor");}//關流ps.close();} }?
第五節 對象流
5.1ObjectInputStreamh和ObjectOutputStream
1.流中流動的數據是對象? ? 將一個對象寫入到本地文件中,被稱為對象的序列化(Serializable)
? ? 將一個本地文件中的對象讀取出來,被稱為對象的反序列化(Deserializable)
2.ObjectInputStream/ObjectOutputStream:增強了讀寫8種基本數據類型,字符串,對象的功能
? ? 注意:
? ? a.序列化對象的類型必須實現Serializable接口。否則不能序列化。
? ? b.如果向將多個對象序列化到本地,可以借助于集合,【思路:將多個對象添加到集合中,將集合的對象寫入到本地文件中,再次讀出來,獲取到的仍然是集合對象,遍歷集合】。 ? ?
3.對象中以下字段不能序列化:
? ? 1)transient 修飾的字段
? ? 2)static 靜態字段
4.在要序列化類中添加serialVersionUID字段,保證序列化和反序列化是同一個類 ??
private static final long serialVersionUID = 100L;
5.讀取到文件尾部的標志:java.io.EOFException ???(End Of File Exception) public class ObjectStreamDemo {public static void main(String[] args) {//objectOutputStreamUsage();objectInputStreamUsage();} ?//寫:將對象進行序列化public static void objectOutputStreamUsage() {//1.實例化一個Person的對象Person person = ?new Person("張三", 10, 'B'); //2.實例化一個對象輸出流的對象ObjectOutputStream output = null;try {output = new ObjectOutputStream(new FileOutputStream(new File("file/person.txt"))); //3.將對象寫入到流中output.writeObject(person); //4.刷新output.flush(); } catch (Exception e) {e.printStackTrace();}finally {try {output.close();} catch (IOException e) {e.printStackTrace();}}} ?//讀:反序列化public static void objectInputStreamUsage() {//1.實例化對象輸入流的對象try {ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("file/person.txt"))); //2.讀取Object object = input.readObject(); //3.對象的向下轉型if(object instanceof Person) {Person p = (Person)object;System.out.println(p);}} catch (Exception e) {e.printStackTrace();}} } 注意:在使用對象流的時候,用于初始化對象流的參數只能是字節流(將對象轉換為二進制的形式,然后再把二進制寫入文件)
補充:
1.合并流 SequenceInputStream
2.字符串流 StringReader / StringWriter
3.管道流 PipedInpurStream / PipedOutputStream
?
第六節 RandomAccessFile類
RandomAccessFile是用來訪問那些保存數據記錄的文件的,可以用seek( )方法來訪問記錄,并進行讀寫。這些記錄的大小不必相同;但是其大小和位置必須是可知的。但是該類僅限于操作文件。案例一:RandomAccessFile類的應用
public class TextDemo01 {public static void main(String[] args) throws Exception {RandomAccessFile file = new RandomAccessFile("file.txt", "rw");// 以下向file文件中寫數據file.writeInt(20);// 占4個字節file.writeDouble(8.236598);// 占8個字節//這個長度寫在當前文件指針的前兩個字節處,可用readShort()讀取file.writeUTF("這是一個UTF字符串");file.writeBoolean(true);// 占1個字節file.writeShort(395);// 占2個字節file.writeLong(2325451l);// 占8個字節file.writeUTF("又是一個UTF字符串");file.writeFloat(35.5f);// 占4個字節file.writeChar('a');// 占2個字節//把文件指針位置設置到文件起始處file.seek(0); ?// 以下從file文件中讀數據,要注意文件指針的位置System.out.println("——————從file文件指定位置讀數據——————");System.out.println(file.readInt());System.out.println(file.readDouble());System.out.println(file.readUTF());//將文件指針跳過3個字節,本例中即跳過了一個boolean值和short值。file.skipBytes(3);System.out.println(file.readLong());//跳過文件中“又是一個UTF字符串”所占字節//注意readShort()方法會移動文件指針,所以不用寫2。file.skipBytes(file.readShort()); System.out.println(file.readFloat()); ?// 以下演示文件復制操作System.out.println("——————文件復制(從file到fileCopy)——————");file.seek(0);RandomAccessFile fileCopy = new RandomAccessFile("fileCopy.txt", "rw");int len = (int) file.length();// 取得文件長度(字節數)byte[] b = new byte[len];//全部讀取file.readFully(b);fileCopy.write(b);System.out.println("復制完成!");} }?
第七節 Properties集合
Properties是Map接口的一個實現類,并且是Hashtable的子類Properties集合中元素也是以鍵值對的形式存在的
Properties特點:
1.存儲屬性名和屬性值
2.屬性名和屬性值都是字符串
3.和流有關系
4.沒有泛型 public class PropertiesDemo {public static void main(String[] args) {//1.實例化一個Properties的對象Properties pro = new Properties();System.out.println(pro);//2.把文件userlist.properties中的鍵值對同步到集合中//實質:讀取/*void load(InputStream inStream); //從輸入流中讀取屬性列表(鍵和元素對)。 */try {pro.load(new BufferedInputStream(new FileInputStream(new File("file/userlist.properties"))));} catch (Exception e) {e.printStackTrace();} System.out.println(pro);//3.向集合中添加一對鍵值對/** Object setProperty(String key, String value) 調用 Hashtable 的方法 put。 */pro.setProperty("address", "china"); System.out.println(pro);try {//4.store//實質:寫入//comments:工作日志pro.store(new BufferedOutputStream(new FileOutputStream(new File("file/userlist.properties"))), "add a pair of key and value");} catch (Exception e) {e.printStackTrace();}} }
?
第八節 裝飾者設計模式
1.裝飾模式指的是在不必改變原類文件和繼承的情況下,動態地擴展一個對象的功能。它是通過創建一個包裝對象,也就是通過裝飾類來包裹真實的對象。(真實對象變成了裝飾類的成員變量!)? ? 2.應用場景:需要擴展一個類的功能,或給一個類添加附加職責。 案例:
1.抽象類 ReadFile -->read抽象方法
2.定義一些ReadFile的實現子類
????ReadTextFile 讀取文本文件
????ReadMusicFile 讀取音樂文件
????ReadVideoFile 讀取視頻文件
3.要求:提高三個子類的功能:帶緩沖 ???
???3.1繼承
?????BufferedReadTextFile繼承ReadTextFile 重寫 read方法
?????BufferedReadMusicFile繼承ReadMusicFile 重寫 read
?????BufferedReadVideoFile繼承ReadVideoFile 重寫 read
?????缺點:1.類體系太龐大 2.耦合性太高
???3.2裝飾者設計模式 :采用組合的關系
?????BufferedReadFile{
?????????private ReadFile readFile;//被強化的類
?????????public BufferedReadFile(ReadFile readFile){
???????????this.readFile=readFile;
?????????}
?????????public void read(){
???????????///重寫方法實現
?????????}
?????}
?????優點:耦合性低,提高重用性
代碼實現:
/*** 抽象人類*/ public abstract class AbstractPerson {public abstract void eat(); } /** *子類1 */ public class Person extends AbstractPerson {String name; public void eat() {System.out.println(name+"正在吃東西.........");}} /*** 子類2*/ public class Person2 extends AbstractPerson{String name;@Overridepublic void eat() {System.out.println(name+"吃......"); } } ? import java.io.BufferedInputStream; /*** 增強Person* @author wgy*/ public class StrongPerson extends AbstractPerson {//使用person創建一個變量AbstractPerson p;public StrongPerson(AbstractPerson p) {this.p = p;}public void eat() {p.eat();System.out.println("抽一口");System.out.println("瞇一會");System.out.println("寫會java代碼"); } }//測試類 public class Test {public static void main(String[] args) {Person benwei=new Person();benwei.name="本偉"; Person2 zhengshuai=new Person2();zhengshuai.name="鄭帥";//裝飾者設計StrongPerson strongPerson=new StrongPerson(benwei);StrongPerson strongPerson2=new StrongPerson(zhengshuai);strongPerson.eat();strongPerson2.eat();} }?
面試題
1.BufferedReader屬于哪種流,它主要是用來做什么的,它里面有那些經典的方法? //字符緩沖流,主要用來增強基礎流,提高讀寫效率。read()讀取字符數組,readLine()一次讀取一行。 2.怎么樣把輸出字節流轉換成輸出字符流,說出它的步驟? //OutputStreamWriter把字節數據指定編碼后轉換成字符流。 3.流一般需要不需要關閉,如果關閉的話在用什么方法,一般要在那個代碼塊里面關閉比較好,處理流(過濾流)是怎么關閉的,如果有多個流互相調用傳入是怎么關閉的? //關閉用close()方法,在finally代碼塊里面關閉比較好。最先創建的流最后關,關閉調用的流時,默認關閉傳入的流。 4.什么叫對象序列化,什么是反序列化,實現對象序列化需要做哪些工作?什么時候對象需要被序列化呢? //將對象寫入本地文件中,叫做對象序列化。 //將對象從本地文件中讀取出來,叫做反序列化。 //實現序列化,需要對象所對應的類實現Serializable接口 //1.需要把對象保存到文件中存儲到物理介質(比如:硬盤)的時候 2.對象需要在網絡上進行傳輸的時候 5.在實現序列化接口的時候一般要生成一個serialVersionUID字段,它叫做什么,一般有什么用 //叫做序列化版本ID,用于鑒別序列化與反序列化是否是同一個類 6.什么是內存流?有什么作用 //以內存為操作點,對數據進行讀寫操作?
總結
- 上一篇: 利润表三点式审阅:以御银股份为例
- 下一篇: DOM是什么?(超详细解释)