生活随笔
收集整理的這篇文章主要介紹了
14:IO之字符字节流
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
字節(jié)流:InputStream ???OutputStream?字節(jié)流:?FileInputStreamFileOutputStreamBufferedInputStreamBufferedOutputStream字符流:Writer ReaderFileReaderFileWriterBufferedReaderBufferedWriter第一 ?IO流概述
一、概述:
IO流是來處理設備間的數(shù)據(jù)傳輸
1、特點:
1)流操作按照數(shù)據(jù)可分為字節(jié)流(處理所有的數(shù)據(jù))和字符流(處理文字,其中包含編碼表,可以指定編碼表防止了編碼表不同而產(chǎn)生亂碼的現(xiàn)象)
2)按照流向分可以分為輸出流和輸入流。
字節(jié)流的抽象基類:InputStream(讀)、OutputStream(寫)
字符流的抽象基類:Reader(讀)、Writer(寫)
注:此四個類派生出來的子類名稱都是以父類名作為子類名的后綴,以前綴為其功能;
第二 ?字符流
一、簡述:
1、字符流中的對象融合了編碼表。使用的是默認的編碼,即當前系統(tǒng)的編碼。
2、字符流只用于處理文字數(shù)據(jù),而字節(jié)流可以任何數(shù)據(jù)。
3、既然IO流是用于操作數(shù)據(jù)的,那么數(shù)據(jù)的最常見體現(xiàn)形式是文件。專門用于操作文件的子類對象:FileWriter、FileReader
二、寫入字符流
- 數(shù)據(jù)的續(xù)寫是通過構造函數(shù) FileWriter(String s,boolean append),根據(jù)給定文件名及指示是否附加寫入數(shù)據(jù)的boolean值來構造FileWriter對象。為true時就是續(xù)寫,為false就是不續(xù)寫。?
- 調用write()方法,將字符串寫入到流中。這里他本身沒有特定的寫方法都是繼承自父類的方法有寫單個字符:write(int?c),寫入字符數(shù)組:write(char[]?cbuf)這里的數(shù)組一般定義成1024的整數(shù)倍,不宜過大,過大容易造成內存溢出。寫入字符數(shù)組的某一部分:write(char[]?cbuf, int?off, int?len),寫入字符串:write(String?str),寫入字符串的某一部分:write(String?str, int?off, int?len)
?*????*?需求:在硬盤上,創(chuàng)建一個文件并寫入一些文字數(shù)據(jù)。???*?找到一個專門用于操作文件的Writer子類對象。FileWriter。??后綴名是父類名。?前綴名是該流對象的功能。???*/??public?class?FileWriterDemo?{??????public?static?void?main(String[]?args)?{??????????method();//寫內容??????????method2();//續(xù)寫內容??????}????????????/*???????*?寫數(shù)據(jù)???????*/??????public?static?void?method(){??????????FileWriter?fw?=?null;??????????try?{??????????????//創(chuàng)建一個FileWriter對象。該對象一被初始化就必須要明確被操作的文件。??????????????//該文件會被存放在指定的目錄下,如果該文件已經(jīng)存在,會被覆蓋??????????????//其實該步就是在明確數(shù)據(jù)要存放的目的地。??????????????fw?=?new?FileWriter("testwrite.txt");//?C:\\testwrite.txt????????????????????????????//調用write方法,將字符串寫入到流中??????????????fw.write("asdsadafsd");????????????????????????????//刷新流對象中的緩沖中的數(shù)據(jù)。??????????????//將數(shù)據(jù)刷到目的地中。??//??????????fw.flush();????????????????????????????//關閉流資源,但是關閉之前會刷新一次內部的緩沖中的數(shù)據(jù)。??????????????//將數(shù)據(jù)刷到目的地中。??????????????//和flush區(qū)別:flush刷新后,流可以繼續(xù)使用,close刷新后,會將流關閉。??//??????????fw.close();??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????}finally{??????????????try?{??????????????????if(fw?!=?null)??????????????????????fw.close();??????????????}?catch?(IOException?e)?{??????????????????e.printStackTrace();??????????????}??????????}??????}????????????/*???????*?在文件原有內容的基礎上續(xù)寫內容???????*/??????public?static?void?method2(){??????????FileWriter?fw?=?null;??????????try?{??????????????fw?=?new?FileWriter("testwrite.txt",?true);??????????????fw.write("\r\nnihao\r\nxiexie");//\r\n是換行符\n是linux下的換行??????????}?catch?(IOException?e)?{??????????????e.printStackTrace();??????????}finally{??????????????if(fw?!=?null){??????????????????try?{??????????????????????fw.close();??????????????????}?catch?(IOException?e)?{??????????????????????e.printStackTrace();??????????????????}??????????????}??????????}??????}??} ?
?三、讀取字符流
四、文件的拷貝:
原理:其實就是將磁盤下的文件數(shù)據(jù)讀取出來,然后寫入磁盤的一個文件中
步驟:
1、在硬盤上創(chuàng)建一個文件,用于存儲讀取出來的文件數(shù)據(jù)
2、定義讀取流和文件關聯(lián)
3、通過不斷讀寫完成數(shù)據(jù)存儲
方式一:讀取一個字符,存入一個字符
方式二:先將讀取的數(shù)據(jù)存入到內存中,再將存入的字符取出寫入硬盤
4、關閉流資源:輸入流資源和輸出流資源。
方法1:/* * 思路: * 1,需要讀取源, * 2,將讀到的源數(shù)據(jù)寫入到目的地。 * 3,既然是操作文本數(shù)據(jù),使用字符流。 * */public class CopyTextTest { public static void main(String[] args) throws IOException { //1,讀取一個已有的文本文件,使用字符讀取流和文件相關聯(lián)。 FileReader fr = new FileReader("IO流_2.txt"); //2,創(chuàng)建一個目的,用于存儲讀到數(shù)據(jù)。 FileWriter fw = new FileWriter("copytext_1.txt"); //3,頻繁的讀寫操作。 int ch = 0; while((ch=fr.read())!=-1){ fw.write(ch); } //4,關閉流資源。先關寫再關讀 fw.close(); fr.close(); }} 方法2:public class CopyTextTest_2 { private static final int BUFFER_SIZE = 1024; public static void main(String[] args) { FileReader fr = null; FileWriter fw = null; try { fr = new FileReader("IO流_2.txt"); fw = new FileWriter("copytest_2.txt"); //創(chuàng)建一個臨時容器,用于緩存讀取到的字符。 char[] buf = new char[BUFFER_SIZE];//這就是緩沖區(qū)。 //定義一個變量記錄讀取到的字符數(shù),(其實就是往數(shù)組里裝的字符個數(shù) ) int len = 0; while((len=fr.read(buf))!=-1){ fw.write(buf, 0, len); } } catch (Exception e) { // System.out.println("讀寫失敗"); throw new RuntimeException("讀寫失敗"); }finally{ if(fw!=null) try { fw.close(); } catch (IOException e) { e.printStackTrace(); } if(fr!=null) try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } }}
第三 ?字符緩沖區(qū)
一、寫入緩沖區(qū)BufferedWriter / * 緩沖區(qū)的出現(xiàn)就是為了提高操作流的效率 * 所以在創(chuàng)建緩沖區(qū)之前必須要先有流對象 * * 緩沖區(qū)提供了一個跨平臺的換行符 new Line(); */ public class BufferedWriterDemo { public static void main(String[] args) { method(); } public static void method() { // 創(chuàng)建一個字符寫入流對象 FileWriter fw = null; BufferedWriter bfw = null; try { fw = new FileWriter("buf.txt"); // 為了提高字符寫入流效率。加入了緩沖技術。其實緩沖區(qū)就是封裝了數(shù)組,不用自己定義數(shù)組,用起來更方便 // 只要將需要被提高效率的流對象作為參數(shù)傳遞給緩沖區(qū)的構造函數(shù)即可。 bfw = new BufferedWriter(fw); for (int x = 0; x < 10; x++) { bfw.write("abcds" + x); bfw.newLine();// 換行在windows中相當于\r\n,在linux中相當于\n } // 記住,只要用到緩沖區(qū),就要記得刷新。 // bufw.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { bfw.close();// 關閉緩沖區(qū)就是在關閉緩沖區(qū)中的流對象,關閉前刷新 } catch (IOException e) { e.printStackTrace(); } } } } private static final String LINE_SEPARATOR = System.getProperty("line.separator"); //使用緩沖區(qū)的寫入方法將數(shù)據(jù)先寫入到緩沖區(qū)中。 // bufw.write("abcdefq"+LINE_SEPARATOR+"hahahha"); // bufw.write("xixiixii"); // bufw.newLine(); 行分隔,就不需要LINE_SEPARATOR,不過只在這里有效 // bufw.write("heheheheh");
二、讀取流緩沖區(qū)BufferedReader該緩沖區(qū)提供了一個一次讀一行的方法readLine(),方便與對文本數(shù)據(jù)的獲取,當返回null時,表示讀到文件末尾。
? ? ? readLine()方法返回的時只返回回車符之前的數(shù)據(jù)內容,并不返回回車符,即讀取的內容中不包含任何行終止符(回車符和換行符)。
--->readLine()方法原理:無論是讀一行,或讀取多個字符,其實最終都是在硬盤上一個一個讀取。所以最終使用的還是read方法一次讀一個
public class BufferedReaderDemo { public static void main(String[] args) { method(); } public static void method(){ //創(chuàng)建一個讀取流對象 FileReader fr = null; BufferedReader bfr = null; try { fr = new FileReader("buf.txt"); //為了提高效率。加入緩沖技術。將字符讀取流對象作為參數(shù)傳遞給緩沖對象的構造函數(shù)。 bfr = new BufferedReader(fr); // char[] buf = new char[1024]; // bfr.read(buf); // int len = 0; // while((len = bfr.read(buf)) != -1){ // System.out.println(new String(buf,0,len)); // } String line = null; while((line = bfr.readLine()) != null){ System.out.println(line); } } catch (IOException e) { e.printStackTrace(); }finally{ try { bfr.close(); } catch (IOException e) { e.printStackTrace(); } } } }
三、通過緩沖技術提高效率復制文件:public class CopyTextByBufTest { //不處理異常,拋出去 public static void main(String[] args) throws IOException { FileReader fr = new FileReader("buf.txt"); BufferedReader bufr = new BufferedReader(fr); FileWriter fw = new FileWriter("buf_copy.txt"); BufferedWriter bufw = new BufferedWriter(fw); String line = null; while ((line = bufr.readLine()) != null) { bufw.write(line); bufw.newLine(); bufw.flush(); } /* * int ch = 0; * * while((ch=bufr.read())!=-1){ * * bufw.write(ch); } */ bufw.close(); bufr.close(); }}處理異常try...catchpublic class CopyByBuffer { public static void main(String[] args) { copyByBuf(); } public static void copyByBuf() { FileWriter fw = null; FileReader fr = null; BufferedWriter bfw = null; BufferedReader bfr = null; try { fw = new FileWriter("C:\\buffertest.txt");//創(chuàng)建寫文件對象 fr = new FileReader("buffertest.txt");//創(chuàng)建讀文件對象 bfw = new BufferedWriter(fw);//使用緩沖區(qū)關聯(lián)讀寫對象 bfr = new BufferedReader(fr); String line = null; while ((line = bfr.readLine()) != null) {//通過讀一行的方式提高效率 bfw.write(line); bfw.newLine();//換行,夸平臺 } } catch (IOException e) { e.printStackTrace(); } finally { if (bfw != null) { try { bfw.close(); } catch (IOException e) { e.printStackTrace(); } } if (bfr != null) { try { bfr.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
四、自定義緩沖區(qū)其實就是模擬一個BufferedReader.?* 分析:?* 緩沖區(qū)中無非就是封裝了一個數(shù)組,并對外提供了更多的方法對數(shù)組進行訪問。?其實這些方法最終操作的都是數(shù)組的角標。?*?* 緩沖的原理:?* 其實就是從源中獲取一批數(shù)據(jù)裝進緩沖區(qū)中。在從緩沖區(qū)中不斷的取出一個一個數(shù)據(jù)。?*?在此次取完后,在從源中繼續(xù)取一批數(shù)據(jù)進緩沖區(qū)。?當源中的數(shù)據(jù)取光時,用-1作為結束標記。public class MyBufferedReader extends Reader { private Reader r; //定義一個數(shù)組作為緩沖區(qū)。 private char[] buf = new char[1024]; //定義一個指針用于操作這個數(shù)組中的元素。當操作到最后一個元素后,指針應該歸零。 private int pos = 0; //定義一個計數(shù)器用于記錄緩沖區(qū)中的數(shù)據(jù)個數(shù)。 當該數(shù)據(jù)減到0,就從源中繼續(xù)獲取數(shù)據(jù)到緩沖區(qū)中。 private int count = 0; MyBufferedReader(Reader r){ this.r = r; } /** * 該方法從緩沖區(qū)中一次取一個字符。 * @return * @throws IOException */ /* public int myRead() throws IOException{ //從源中獲取一批數(shù)據(jù)到緩沖區(qū)中。需要先做判斷,只有計數(shù)器為0時,才需要從源中獲取數(shù)據(jù)。 if(count==0){ count = r.read(buf); //這是在底層 if(count<0)//沒有了 return -1; //每次獲取數(shù)據(jù)到緩沖區(qū)后,角標歸零(第一個read,底層)創(chuàng)建了一個數(shù)組。 pos = 0; char ch = buf[pos]; // 然后調用一次(第二個)read,返回一個a,再調用返回b,角標取一個,count減一個 pos++; count--; return ch; } else if(count>0){//第二次調用的時候count就不為0了, 不需要count = r.read(buf)這一步了 char ch = buf[pos]; pos++; count--; return ch; }*/
優(yōu)化后 public int myRead() throws IOException{ if(count==0){ count = r.read(buf); pos = 0; } if(count<0) return -1; char ch = buf[pos++]; count--; return ch; } 五、模擬ReadLinepublic String myReadLine() throws IOException{ // 定義一個臨時容器,原BufferedReader封裝的是字符數(shù)組,這里定義StringBuilder演示原理 StringBuilder sb = new StringBuilder(); int ch = 0; while((ch = myRead())!=-1){ if(ch=='\r') //如是'\r'繼續(xù)往下讀 continue; if(ch=='\n') //讀到'\n'就停止讀,然后將這些數(shù)據(jù)返回 return sb.toString(); //將從緩沖區(qū)中讀到的字符,存儲到緩存行數(shù)據(jù)的緩沖區(qū)中。 sb.append((char)ch); } if(sb.length()!=0) //最后沒有空格,說明有東西,返回, //這里是防止最后一行沒有回車符的情況 return sb.toString(); return null; } public void myClose() throws IOException { r.close(); } @Override public int read(char[] cbuf, int off, int len) throws IOException { return 0; } @Override public void close() throws IOException { } } 運行 ReadLine public class MyBufferedReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("buf.txt"); MyBufferedReader bufr = new MyBufferedReader(fr); String line = null; while((line=bufr.myReadLine())!=null){ System.out.println(line); } bufr.myClose(); Collections.reverseOrder(); HashMap map = null; map.values(); } }六、LineNumberReader(功能增強的讀)在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設置行號:
setLineNumber()和getLineNumber()
public class LineNumberReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("IO流_2.txt"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; lnr.setLineNumber(100);// 默認是0 while ((line = lnr.readLine()) != null) { System.out.println(lnr.getLineNumber() + ":" + line); } lnr.close(); }}
第四 ?裝飾設計模式
裝飾設計模式: (buffer就是裝飾設計模式)?對一組對象的功能進行增強時,就可以使用該模式進行問題的解決。??裝飾和繼承都能實現(xiàn)一樣的特點:進行功能的擴展增強。?有什么區(qū)別呢??首先有一個繼承體系。Writer (抽取了一個寫的)?|--TextWriter?(隨便寫的):用于操作文本?|--MediaWriter:用于操作媒體。?想要對操作的動作進行效率的提高。按照面向對象,可以通過繼承對具體的進行功能的擴展。效率提高需要加入緩沖技術。?Writer?|--TextWriter:用于操作文本? |--BufferTextWriter:加入了緩沖技術的操作文本的對象。?|--MediaWriter:用于操作媒體。? |--BufferMediaWriter:到這里就哦了。但是這樣做好像并不理想。如果這個體系進行功能擴展,有多了流對象。那么這個流要提高效率,是不是也要產(chǎn)生子類呢?是。這時就會發(fā)現(xiàn)只為提高功能,進行的繼承,導致繼承體系越來越臃腫。不夠靈活。重新思考這個問題?既然加入的都是同一種技術--緩沖。前一種是讓緩沖和具體的對象相結合。可不可以將緩沖進行單獨的封裝,哪個對象需要緩沖就將哪個對象和緩沖關聯(lián)。class Buffer { Buffer(TextWriter w) // 要緩沖誰就加入進來 { } Buffer(MediaWirter w) // 要緩沖誰就加入進來 { }} // 但是這樣做,來新對象還得加入,比較麻煩// 都能寫入,為了名字有意義,寫成BufferWriterclass BufferWriter extends Writer { BufferWriter(Writer w) { }}Writer?|--TextWriter:用于操作文本?|--MediaWriter:用于操作媒體。?|--BufferWriter:用于提高效率。
??裝飾比繼承靈活。?特點:裝飾類和被裝飾類都必須所屬同一個接口或者父類。?有個類想要增強,可以用裝飾設計模式,把被裝飾的類往里傳進來就可以
第五 ?字節(jié)流
一、概述:
1、字節(jié)流和字符流的原理是相似的,而字符流是基于字節(jié)流的,字節(jié)流可以操作如媒體等其他數(shù)據(jù),如媒體(MP3,圖片,視頻)等
2、由于媒體數(shù)據(jù)中都是以字節(jié)存儲的,所以,字節(jié)流對象可直接對媒體進行操作,而不用再進行刷流動作。
3、InputStream ? ? ---> ?輸入流(讀) ?OutputStream ?---> ?輸出流(寫)
4、為何不用進行刷流動作:因為字節(jié)流操作的是字節(jié),即數(shù)據(jù)的最小單位,不需要像字符流一樣要進行轉換為字節(jié)。可直接將字節(jié)寫入到指定文件中,但是需要在寫代碼的時候,如果有字符串,要將字符串轉為字節(jié)數(shù)組再進行操作。
5、FileInputStream特有方法:int available() ---> ?返回數(shù)據(jù)字節(jié)的長度,包含終止符
在定義字節(jié)數(shù)組長度的時候,可以用到這個方法:byte[] = new byte[fos.available()] ? (fos為字節(jié)流對象)但是,對于這個方法要慎用,如果字節(jié)過大,超過jvm所承受的大小(一般內存為64M),就會內存溢出。
實例: / * 字節(jié)流操作 * InputStream OutputStream * */ public class FileStreamDemo { public static void main(String[] args) { // writeFile(); // readFile_1(); // readFile_2(); readFile_3(); } /* * 對字節(jié)流讀操作的第一種方式 通過read()方法讀取一個字節(jié) */ public static void readFile_1() { FileInputStream fis = null;// 定義字節(jié)輸入流 try { fis = new FileInputStream("fos.txt");// 指定輸入流和文件關聯(lián) int ch = 0; while ((ch = fis.read()) != -1) {// 讀取操作 System.out.println((char) ch); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fis != null)// 判空,提高程序的健壯性 fis.close(); } catch (IOException e) { e.printStackTrace(); } } } /* * 對字節(jié)流讀操作的第二種方式 通過read(byte[])方法讀取字節(jié)數(shù)組 */ public static void readFile_2() { FileInputStream fis = null; try { fis = new FileInputStream("fos.txt"); byte[] byf = new byte[1024]; int len = 0; while ((len = fis.read(byf)) != -1) { System.out.println(new String(byf, 0, len)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); } } } /* * 對字節(jié)流讀操作的第三種方式 通過字節(jié)流的available()方法獲取到文件大小,定義一個大小剛剛好的數(shù)組,無需循環(huán) 但是,這種方式操作較大數(shù)據(jù)時容易內存溢出,所以要慎用 首選的還是定義1024的整數(shù)倍數(shù)組 */ public static void readFile_3() { FileInputStream fis = null; try { fis = new FileInputStream("fos.txt"); // 通過這樣的方式定義一個剛剛好的數(shù)組 // 這種方法慎用,如果文件不大,可以用這個方法 byte[] byf = new byte[fis.available()];// fis.available()獲取文件大小 fis.read(byf); System.out.println(new String(byf)); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } /* * 對字節(jié)流進行寫操作 */ public static void writeFile() { FileOutputStream fos = null; try { fos = new FileOutputStream("fos.txt");//定義字節(jié)寫出流和文件關聯(lián) fos.write("abcds".getBytes());// str.getBytes()將String轉化成字節(jié)數(shù)組 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) try { fos.close();// 因為字節(jié)流沒有用到緩沖區(qū),所以不需要刷新,但必須關閉資源 } catch (IOException e) { e.printStackTrace(); } } } }二、通過字節(jié)流復制媒體文件思路:
1、用字節(jié)流讀取流對象和媒體文件相關聯(lián)
2、用字節(jié)寫入流對象,創(chuàng)建一個媒體文件,用于存儲獲取到的媒體文件數(shù)據(jù)
3、通過循環(huán)讀寫,完成數(shù)據(jù)的存儲
4、關閉資源
* 通過字節(jié)流拷貝圖片 */ public class CopyPicture { public static void main(String[] args) { copyPic(); } public static void copyPic() { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("1.jpg"); fos = new FileOutputStream("C:\\1.jpg"); byte[] byf = new byte[1024]; int len = 0; while ((len = fis.read(byf)) != -1) {// 將數(shù)據(jù)讀取到數(shù)組中 fos.write(byf, 0, len);// 寫入數(shù)組中的有效數(shù)據(jù) } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 有多個流不能一起關閉,要分別關閉 if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } } // 千萬不要用,效率沒有! public static void copy_4() throws IOException { FileInputStream fis = new FileInputStream("c:\\0.mp3"); FileOutputStream fos = new FileOutputStream("c:\\4.mp3"); int ch = 0; while((ch =fis.read())!=-1){ fos.write(ch); } fos.close(); fis.close(); } //不建議。 public static void copy_3() throws IOException { FileInputStream fis = new FileInputStream("c:\\0.mp3"); FileOutputStream fos = new FileOutputStream("c:\\3.mp3"); byte[] buf = new byte[fis.available()]; fis.read(buf); fos.write(buf); fos.close(); fis.close(); }//提高效率public static void copy_2() throws IOException { FileInputStream fis = new FileInputStream("c:\\0.mp3"); BufferedInputStream bufis = new BufferedInputStream(fis); FileOutputStream fos = new FileOutputStream("c:\\2.mp3"); BufferedOutputStream bufos = new BufferedOutputStream(fos); int ch = 0; while((ch=bufis.read())!=-1){ bufos.write(ch); } bufos.close(); bufis.close(); }三、字節(jié)流緩沖區(qū)1、緩沖區(qū)的出現(xiàn)無非就是提高了流的讀寫效率,當然也就是因為這樣,所以緩沖區(qū)的使用頻率也是相當高的,所以要做必要性的掌握。
2、字節(jié)流緩沖區(qū)讀寫的特點:
這里沒有什么特殊的讀寫方法,就是read()讀一個字節(jié),read(byte[])讀數(shù)組的方法。寫write(int?b)寫一個自己,write(byte[])寫數(shù)組的方法。
注:需要注意個地方,write方法只寫出二進制的最后八位。原理:將數(shù)據(jù)拷貝一部分,讀取一部分,循環(huán),直到數(shù)據(jù)全部讀取完畢。
1)先從數(shù)據(jù)中抓取固定數(shù)組長度的字節(jié),存入定義的數(shù)組中,再通過然后再通過read()方法讀取數(shù)組中的元素,存入緩沖區(qū)
2)循環(huán)這個動作,知道最后取出一組數(shù)據(jù)存入數(shù)組,可能數(shù)組并未填滿,同樣也取出包含的元素
3)每次取出的時候,都有一個指針在移動,取到數(shù)組結尾就自動回到數(shù)組頭部,這樣指針在自增
4)取出的時候,數(shù)組中的元素再減少,取出一個,就減少一個,直到減到0即數(shù)組取完
5)到了文件的結尾處,存入最后一組數(shù)據(jù),當取完數(shù)組中的元素,就會減少到0,這是全部數(shù)據(jù)就取完了
3、自定義字節(jié)緩沖區(qū):
* 自定義字節(jié)流緩沖區(qū) */ public class MyBufferedInputStream { private InputStream in; private byte[] buf = new byte[1024]; private int pos;// 定義數(shù)組的指針 private int count;// 定義計數(shù)器 MyBufferedInputStream(InputStream in) { this.in = in; } // 一次讀一個字節(jié),從緩沖區(qū)(數(shù)組)中取得 public int myRead() throws IOException { // 通過in對象讀取數(shù)據(jù)并存放在buf數(shù)組中 if (count == 0) { count = in.read(buf); if (count < 0) { return -1; } pos = 0; byte b = buf[pos]; count--; pos++; return b & 255;// &255是因為存放的是二進制,也就是可能前八位是11111111,提升為int還是-1,就直接return了, // &255就是讓前面補0 /* * 11111111 11111111 11111111 11111111 * &00000000 00000000 00000000 11111111 * ------------------------------------ * 00000000 00000000 00000000 11111111 */ }else if(count>0){ byte b = buf[pos]; count--; pos++; return b&255;//&0xff } return -1; } public void myClose() throws IOException{ in.close(); } }注:取出的是byte型,返回的是int型,這里存在提升的動作,當byte中的八位全為1的時候是byte的-1,提升為int類型,就變?yōu)閕nt型的-1,為-1時程序就停止循環(huán)了,read循環(huán)條件就結束了,變?yōu)?1的原因是由于在提升時,將byte的八位前都補的是1,即32位的數(shù)都是1,即為int型的-1了。如何保證提升后的最后八位仍為1呢?就需要將前24位補0,就可以保留原字節(jié)數(shù)據(jù)不變,又可以避免轉為int型出現(xiàn)-1的情況;那么要如何做呢?這就需要將提升為int的數(shù)據(jù)和前24位為0,后八位仍為原字節(jié)數(shù)據(jù)的這個值做與運算。即和255做與運算即可。說到了這里應該也明白了為什么Read方法返回值為int類型了。
第六 ?轉換流
轉換流:轉換流可以實現(xiàn)字節(jié)數(shù)據(jù)和字符數(shù)據(jù)的相互轉換方便與操作,而且在轉換的時候可以指定編碼,這也是該流最具特色的地方。:InputStreamReader 是字節(jié)流通向字符流的橋梁
OutputStreamWriter 是字符流通向字節(jié)流的橋梁
轉換流的子類和轉換流的區(qū)別?
InputStreamReader ? 字節(jié)-->字符??|--FileReader : 字節(jié)流+本地默認碼表。OutputStreamWriter ?字符-->字節(jié)?|--FileWriter?
什么時候使用轉換流呢?1,源或者目的對應的設備是字節(jié)流,但是操作的卻是文本數(shù)據(jù),可以使用轉換作為橋梁。提高對文本操作的便捷。2,一旦操作文本涉及到具體的指定編碼表時,必須使用轉換流 。BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
? ? ? //獲取鍵盤錄入對象??
?????????InputStream?in?=?System.in;?????????????????????//將字節(jié)流對象轉換成字符流對象???????????InputStreamReader?isr?=?new?InputStreamReader(in);?????????????????????//將字符流對象用緩沖技術高效處理???????????BufferedReader?bufr?=?new?BufferedReader(isr);? ? ? ? ?//?鍵盤錄入最常見的寫法??? ? ? ? ?BufferedReader?bufr?=?new?BufferedReader(new ?InputStreamReader(System.in)); ?
字符流轉字節(jié)流:
? ? ? ? //?操作輸出??????????//?獲取輸出流???????????OutputStream?out?=?System.out;???????????//將字符流轉換成字節(jié)流,OutputStreamWriter字符流通向字節(jié)流的橋梁???????????OutputStreamWriter?osw?=?new?OutputStreamWriter(out);???????????BufferedWriter?bfw?=?new?BufferedWriter(osw);//高效緩沖區(qū)
獲取鍵盤輸入:鍵盤輸入都是字節(jié),所以用到字節(jié)流與標準輸入流相關聯(lián)就可以把輸入的數(shù)據(jù)獲取到流中,以達到數(shù)據(jù)的操作效果。
* 獲取鍵盤錄入 public class ReadIn { public static void main(String[] args) { // method_1(); // method_2(); InputStreamReaderDemo(); } /* * 獲取鍵盤錄入 */ public static void method_1() { InputStream in = System.in;// 定義輸入流與鍵盤輸入流相關聯(lián) int ch = 0; try { while ((ch = in.read()) != -1) { System.out.println(ch); } } catch (IOException e) { e.printStackTrace(); } } /* * 需求:通過鍵盤錄入數(shù)據(jù)。 當錄入一行數(shù)據(jù)后,就將該行數(shù)據(jù)進行打印。 如果錄入的數(shù)據(jù)是over,那么停止錄入。 * 1,因為鍵盤錄入只讀取一個字節(jié),要判斷是否是over,需要將讀取到的字節(jié)拼成字符串。 * 2,那就需要一個容器。StringBuilder. * 3,在用戶回車之前將錄入的數(shù)據(jù)變成字符串判斷即可。 */ public static void method_2() { InputStream in = System.in; StringBuilder sb = new StringBuilder();// 定義一個臨時容器 while (true) { int ch = 0; try { ch = in.read(); if (ch == '\r')// windows中換行符為\r\n continue; if (ch == '\n') { String s = sb.toString();// 當讀到一行的結束標記時,把改行數(shù)據(jù)變成字符串 if ("over".equals(s)) break; System.out.println(s.toUpperCase()); //變成大寫 sb.delete(0, sb.length());// 清空容器 ,不清空會將上次輸入的和這次輸入的都輸出 } else { sb.append((char) ch); //將讀取到的字節(jié)存儲到StringBuilder中。 } } catch (IOException e) { e.printStackTrace(); } } } // ************************************************************************** /* * 通過上面錄入一行數(shù)據(jù),發(fā)現(xiàn)其方法類似于readLine方法 但是readLine方法是字符流緩沖區(qū)的方法,所以需要把字節(jié)流轉換成字符流進行操作 * 需要用到InputStreamReader方法進行轉換,InputStreamReader字節(jié)通向字符的橋梁 * * 轉換流 */ public static void InputStreamReaderDemo() { BufferedReader bufr = null; try { // 源為文件 bufr = new BufferedReader(new InputStreamReader( new FileInputStream("buf.txt"))); } catch (FileNotFoundException e2) { e2.printStackTrace(); } // 操作輸出 // 目的地是控制臺 BufferedWriter bfw = new BufferedWriter(new OutputStreamWriter( System.out)); // 目的地是文件 // BufferedWriter bfw = null; // try { // bfw = new BufferedWriter(new OutputStreamWriter(new // FileOutputStream("out.txt"))); // } catch (FileNotFoundException e1) { // e1.printStackTrace(); // } String line = null; try { while ((line = bufr.readLine()) != null) { if ("over".equals(line)) { break; } bfw.write(line.toUpperCase()); bfw.newLine();// 換行 bfw.flush();// 數(shù)據(jù)存放在緩沖區(qū),所以需要刷新 } } catch (IOException e) { e.printStackTrace(); } finally { try { bufr.close(); } catch (IOException e) { e.printStackTrace(); } } } }不處理異常public class TransStreamDemo2 { public static void main(String[] args) throws IOException { /* * 1,需求:將鍵盤錄入的數(shù)據(jù)寫入到一個文件中。 * * 2,需求:將一個文本文件內容顯示在控制臺上。 * * 3,需求:將一個文件文件中的內容復制到的另一個文件中。 */ BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"))); String line = null; while((line=bufr.readLine())!=null){ if("over".equals(line)) break; bufw.write(line.toUpperCase()); //變成大寫 bufw.newLine(); bufw.flush(); } } }
第七 ?流的操作規(guī)律
之所以要弄清楚這個規(guī)律,是因為流對象太多,開發(fā)時不知道用哪個對象合適。想要知道開發(fā)時用到哪些對象。只要通過四個明確即可。1,明確源和目的(匯)?源:InputStream ?Reader?目的:OutputStream ?Writer2,明確數(shù)據(jù)是否是純文本數(shù)據(jù)。?源:是純文本:Reader? 否:InputStream?目的:是純文本 Writer? 否:OutputStream??到這里,就可以明確需求中具體要使用哪個體系。?3,明確具體的設備。?源設備:? 硬盤:File? 鍵盤:System.in? 內存:數(shù)組? 網(wǎng)絡:Socket流??目的設備:? 硬盤:File? 控制臺:System.out? 內存:數(shù)組? 網(wǎng)絡:Socket流4,是否需要其他額外功能。?1,是否需要高效(緩沖區(qū));? 是,就加上buffer.?2,轉換。?需求1:復制一個文本文件。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本?? 是!? 源:Reader? 目的:Writer??3,明確具體設備。? 源:? ?硬盤:File? 目的:? ?硬盤:File?? FileReader fr = new FileReader("a.txt");? FileWriter fw = new FileWriter("b.txt");??4,需要額外功能嗎?? 需要,需要高效。? BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));? BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));?================================================需求2:讀取鍵盤錄入信息,并寫入到一個文件中。??1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確設備? 源:? ?鍵盤。System.in? 目的:? ?硬盤。File? ?? InputStream in = System.in;? FileWriter fw = new FileWriter("b.txt");? 這樣做可以完成,但是麻煩。將讀取的字節(jié)數(shù)據(jù)轉成字符串。再由字符流操作。?4,需要額外功能嗎?? 需要。轉換。 將字節(jié)流轉成字符流。因為名確的源是Reader,這樣操作文本數(shù)據(jù)做便捷。? ?所以要將已有的字節(jié)流轉成字符流。使用字節(jié)-->字符 。InputStreamReader? InputStreamReader isr = new InputStreamReader(System.in);? FileWriter fw = new FileWriter("b.txt");?? 還需要功能嗎?? 需要:想高效。? BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));? BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));?? ??===================================================?需求3:將一個文本文件數(shù)據(jù)顯示在控制臺上。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確具體設備? 源:? ?硬盤:File? 目的:? ?控制臺:System.out? ?? FileReader fr = new FileReader("a.txt");? OutputStream out = System.out;//PrintStream?4,需要額外功能嗎?? 需要,轉換。? FileReader fr= new FileReader("a.txt");? OutputStreamWriter osw = new OutputStreamWriter(System.out);? 需要,高效。? BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));? BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));?================================================================需求4:讀取鍵盤錄入數(shù)據(jù),顯示在控制臺上。?1,明確源和目的。? 源:InputStream Reader? 目的:OutputStream ?Writer?2,是否是純文本呢?? 是,? 源:Reader? 目的:Writer?3,明確設備。? 源:? ?鍵盤:System.in? 目的:? ?控制臺:System.out?? InputStream in = System.in;? OutputStream out = System.out;??4,明確額外功能?? 需要轉換,因為都是字節(jié)流,但是操作的卻是文本數(shù)據(jù)。? 所以使用字符流操作起來更為便捷。? InputStreamReader isr = new InputStreamReader(System.in);? OutputStreamWriter osw = new OutputStreamWriter(System.out);?? 為了將其高效。? BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));? BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));??============================================================5,將一個中文字符串數(shù)據(jù)按照指定的編碼表寫入到一個文本文件中.??1,目的。OutputStream,Writer?2,是純文本,Writer。?3,設備:硬盤File?FileWriter fw = new FileWriter("a.txt");?fw.write("你好");??注意:既然需求中已經(jīng)明確了指定編碼表的動作。?那就不可以使用FileWriter,因為FileWriter內部是使用默認的本地碼表。?只能使用其父類。OutputStreamWriter.?OutputStreamWriter接收一個字節(jié)輸出流對象,既然是操作文件,那么該對象應該是FileOutputStream??OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName(編碼));??需要高效嗎??BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));??演示:將一個中文字符串數(shù)據(jù)按照指定的編碼表寫入到一個文本文件中.?寫:
public static void writeText_2() throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "gbk_3.txt"), "GBK"); // OutputStreamWriter osw = new OutputStreamWriter(new // FileOutputStream("gbk_3.txt"),"GBK"); // FileWriter fw = new FileWriter("gbk_1.txt"); /* * 這兩句代碼的功能是等同的。 FileWriter:其實就是轉換流指定了本機默認碼表的體現(xiàn)。而且這個轉換流的子類對象,可以方便操作文本文件。 * 簡單說:操作文件的字節(jié)流+本機默認的編碼表。 這是按照默認碼表來操作文件的便捷類。 * * 如果操作文本文件需要明確具體的編碼。FileWriter就不行了。必須用轉換流 */ osw.write("你好"); osw.close(); } public static void writeText_3() throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream( "u8_1.txt"), "UTF-8"); osw.write("你好"); osw.close(); }
讀:
public static void readText_1() throws IOException { FileReader fr = new FileReader("gbk_1.txt"); char[] buf = new char[10]; int len = fr.read(buf); String str = new String(buf,0,len); System.out.println(str); fr.close(); } //用utf-8讀默認的編碼文件 public static void readText_2() throws IOException, FileNotFoundException { InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk_1.txt"),"utf-8"); char[] buf = new char[10]; int len = isr.read(buf); String str = new String(buf,0,len); System.out.println(str); isr.close(); } } }
?
來自為知筆記(Wiz)
轉載于:https://www.cnblogs.com/sixrain/p/4912372.html
總結
以上是生活随笔為你收集整理的14:IO之字符字节流的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。