[19/03/30-星期六] IO技术_四大抽象类_ 字节流( 字节输入流 InputStream 、字符输出流 OutputStream )_(含字节文件缓冲流)...
一、概念及分類
? ? ? ?InputStream(輸入流)/OutputStream(輸出流)是所有字節輸入輸出流的父類
【注】輸入流和輸出流的是按程序運行所在的內存的角度劃分的
? ? ? ? ? 字節流操作的數據單元是8的字節,字符流操作的數據單元是16位的字符
【流的概念】
——————————
ooooooooooooooooo
—————————— (輸入流模型,文件從頭(左邊)到尾(右邊),)
↑,(記錄指針)
?
每個‘’o“”看出一個"水滴",不管是字節流還是字符流,每個水滴是最小的輸入/輸出單位,對于字節流而言,每個水滴是1個字節(8位)
對于字符流而言,每個水滴是1個字符(16位)。輸入流使用隱含的記錄指針來表示當前正準備從哪個水滴開始讀取,每當程序從InputStream或
Reader里取出一個或多個水滴后,指針自動向后(指針從左往右)移動。此外,還可以控制記錄指針的移動,比如說設置偏移量off。
對于輸出流相對于把水滴放入輸入流水管中,也有記錄指針自動控制移動,每當程序向OutputStream或Writer輸出一個或多個水滴后,記錄指針自
動向后移動。
?
1、InputStream(重要的是 文件操作字節流FileInputStream子類和帶8KB緩沖數組的ButteredInputStream)
? ? ??此抽象類是表示字節輸入流的所有類的父類。InputSteam是一個抽象類,它不可以實例化。 數據的讀取需要由它的子類來實現。根據節點的不同,
它派生了不同的節點流子類 。?繼承自InputSteam的流都是用于向程序中輸入數據,且數據的單位為字節(8 bit)。
? ? ??int read():從(所寫程序的源文件中)一個一個字節讀取數據,并將字節的值作為int類型返回(0-255之間的一個值)。
? ? ? ? ? ? ? ? ? ? ? ? ?如果未讀出字節則返回-1(返回值為-1表示讀取結束)。
? ? ? int (byte b[]) :一段一段的讀取數據
? ? ??void close(): (通知操作系統)關閉輸入流對象,釋放相關系統資源。
【代碼示例】字節文件操作流_不帶緩沖數組 (FileInputStream)
1 /*輸入流(從數據源輸入到程序中) :數據源-->>程序,是從數據源(源文件、類比書本上知識)讀取(read)數據到程序(目標程序、大腦) 2 * 輸入流對應read()方法 ,從書本上流入(輸入、Input)到大腦中,而大腦需要讀取(read)書本上的知識 3 * 步驟:選擇源數據-->>選擇流(選哪個搬家公司)-->>操作(一個一個讀/寫or一段一段讀/寫,即怎么搬家)-->>釋放系統資源(讓搬家公司走) 4 * 5 一、 read():從輸入流中讀取一個8位的字節的數據,(程序自動)把它轉成0-255之間的整數,并返回這個整數。 采用逐個讀取字節 6 1.從讀取流讀取的是一個一個字節 7 2.返回的是字節的(0-255)內的字節值 ASCII碼 8 3.讀一個下次就自動到下一個,如果碰到-1說明沒有值了. 9 10 二、 read(byte[] bytes): 從輸入流中最多讀取bytes.length(定量)個字節的數據(最后一次可能不滿,前面肯定是滿的),并將 11 它們存在byte數組中,返回實際讀取的字節數 12 1.從讀取流讀取一定數量的字節,如果比如文件總共是102個字節 13 2.我們定義的數組長度是10,那么默認前面10次都是讀取10個長度 14 3.最后一次不夠十個,那么讀取的是2個 15 4.這十一次,每次都是放入10個長度的數組. 16 17 三、read(byte[] bytes,int off ,int len):從輸入流中最多讀取len個字節(字節可以設定,但不超過數組最大容量)將其存在bytes 18 數組中,但放入數組的時候并不是從起點開始的是從可以自己設定的off位置開始的(當然可以設為0,表示從起點開始)返回實際讀取的字節數 19 1.從讀取流讀取一定數量的字節,如果比如文件總共是102個字節 20 2.我們定義的數組長度是10,但是這里我們寫read(bytes,0,9)那么每次往里面添加的(將只會是9個長度),就要讀12次,最后一次放入3個. 21 3.所以一般讀取流都不用這個而是用上一個方法:read(byte[]); 22 23 void close()關閉輸入流并釋放與該流相關的所有系統資源 24 */ 25 package cn.sxt.test; 26 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 32 33 public class Test_0329_InputStream { 34 public static void main(String[] args) throws IOException { //與外界(操作系統讀寫)有聯系,可能有異常,所以拋出異常 35 //1、選擇源文件 內容為:hello China I love you 36 File file=new File("編碼_GBK_純英文.txt"); //GBK編碼 英文占一個字節 37 //2、選擇流 FileInputStream 順序的讀取文件,只要不關閉每次調用read()方法就順序的讀取源數據中【剩余】的內容 38 InputStream iStream=new FileInputStream(file); 39 40 //這種寫法也對,綜合了第一步和第二步,更加簡單 41 FileInputStream iStream2=new FileInputStream("編碼_GBK_純英文.txt"); 42 43 //3-1-1、有點繞的寫法 測試read()方法選擇操作 (讀/寫) 循環讀取 一個一個字節去讀 44 /*int temp; 45 while ((temp=iStream.read())!=-1) { 46 System.out.print((char)temp); 47 48 }*/ 49 //3-1-2、最可以讓人理解的一種寫法 50 /*int b=0;//b的作用記住每次讀取的一個字節的整形返回值(英文、數字及常見符號其實就是ASCII碼的值) 51 while (true) { 52 b=iStream.read(); 53 if (b==-1) {//如果讀出字節為-1 跳出整個循環表示已經到文件末尾 54 break; 55 } 56 System.out.print((char)b); 57 }*/ 58 59 60 /*//3-2 測試read(byte[] b)方法 將數據讀取到準備好的字節數組(byte[],這里名字叫datas)中,同時返回讀取字節數組的實際長度 61 // 如果到結尾,返回-1 62 byte datas[]=new byte[4]; //新建一個大小為4的字節(byte)數組,名字叫datas. 63 int length=iStream.read(datas);//length=4 就是每次讀取時字符的實際長度,因為讀到最后是可能剩余的字符不足4 可能為3 64 //當最后讀取完后,再去讀取時發現沒有了,則返回-1 表示讀取結束 65 //String msg2=new String(datas, 0, datas.length, "GBK"); 標準解碼語句 66 String msg2=new String(datas, 0, length); //字節數組解碼成字符 67 System.out.println(msg2); //輸出 "hell" 因為沒用循環只表示一次讀取的情況,一次只讀取了4個字節的字符 68 //可以加循環或者加大datas數組的大小,讓其一次讀完 69 */ 70 71 72 73 //3-3 測試read(byte[] b,int off,int len)方法 。讀取任意一段字節。off(偏移量):表示把源文件中從頭(即下標)開始讀取到的字節數存在 74 //datas數組下標為off開始的位置,讀取源文件的長度為len,也就是在datas數組中下標為off開始位置存儲長度為len字節的源數據 75 byte datas[]=new byte[7]; 76 77 //雖然定義的數組datas大小為7個字節,但每次只添加4個字節的字符,表示使用datas數組的實際使用空間為4個字節。 78 //2的含義:表示把讀取到數據存在datas數組下標為2的位置 即datas[2]='h'意味著datas[0]=datas[1]=0,即null空字符 79 //4的含義:在datas數組中從下標為2的位置開始存儲一段長度為4的源數據字節(從源文件開頭讀的) 即 80 //datas[2]=104,'h';datas[3]=101,'e';datas[4]=108,'l';datas[5]=108,'l' datas[6]=0 ,null 81 int length=iStream.read(datas, 2, 4);//read()方法返回length=4 4:代表實際存儲一段長度為4的字節,其它下標位置存儲為空 82 System.out.println(length); 83 for (int i=0;i<datas.length ;i++) { 84 System.out.printf("datas[%d]=%d;",i,datas[i]); 85 86 } 87 88 89 //ASCII碼 (范圍 0-127)null 0;a 97;b 98;c 99;d 100;e 101;f 102; g 103 ;h 104;i 105; g 106;k 107;l 108 90 //字節數組解碼成字符 從數組datas下標為1的地方開始解碼(只測試純英文的情況,含中文數字可能報異常)。 91 //解碼長度length=4,代表解碼一段長度為4的字節碼文件 輸出" hel";也可以length-1 解碼一段長度為3的datas數組文件 92 //輸出結果為" he" 93 String msg2=new String(datas, 1, length); //String 構造方法,字節-->>字符 94 System.out.println("\n"+msg2); 95 96 97 /* 98 int data1=iStream.read();//讀取第一個字符 "h" 輸出的是"h"的ASCLL碼104 99 int data2=iStream.read();//讀取第二個字符 "e" 100 int data3=iStream.read();//讀取第三個字符 "l" 101 System.out.println(data1);//返回的數據的ASCII碼需要強制轉型 。文件的末尾如果沒有數據返回-1 102 System.out.println((char)data2); 103 System.out.println((char)data3);*/ 104 105 //4、釋放資源 106 iStream.close(); 107 108 } 109 110 }
?
2、 OutputStream??(重要的是 文件操作字節流FileOutputStream子類和帶8KB緩沖數組的ButteredOutputStream子類))
? ? ??此抽象類是表示字節輸出流的所有類的父類。輸出流接收輸出字節并將這些字節發送到某個目的地。
? ? ??void write(int n):向目的地(即所寫程序)中寫入一個字節。
? ? ? void write(byte b[]):一段一段去寫數據
? ? ? void? (byte b[],int off,int len) :從指定的字節數組寫入len字節,從偏移量off開始輸出到此輸出流
? ? ? void flush() :刷新此輸出流,并強制任何緩沖的輸出字節流被寫出。
? ? ??void close(): (通知操作系統)關閉輸出流對象,釋放相關系統資源。
【代碼示例】
1 /* 2 *輸出(Output)流(Stream)。 3 *通過寫字( write()方法 ),把大腦中的知識(類比程序)輸出(寫出)到(Output)外界的作業本上(類比源文件,如a.txt文件),去更改作業本上原有的內容 4 步驟:創建源-->>選擇流-->>操作(寫出內容)-->>釋放資源 5 void write(int n): 向目的地(即所寫程序)中寫入一個字節。逐個寫入字節 6 n應是讀取到的源數據編碼值。如把"love"寫入目標文件, 一個一個字節讀,讀到'l' 此時這里的n應該是'l'的ASCII碼值108,依次往下讀 7 while(( len=in.read() )!=-1){ 8 out.write(len); 9 } 這段程序完成文件的復制,表示讀到的十進制編碼值(0-255之間,英文就是ASCII碼),然后把這個值送到write()方法中,讓其執行寫入操作 10 但是效率很低,它是讀一個字節取到編碼值后,然后再根據編碼值去寫入,循環往復。一個字節一個字節讀和寫.好比很多貨物但每次只送一個, 11 循環往復,盡管車廂很大,只裝一個,浪費油。電腦中就是浪費內存,不停進行磁盤讀寫,速度很慢。 12 13 void write(byte b[]):一段一段去寫數據。把參數b指定的字節數組的【所有字節】寫入到目標文件中去。批量寫入 14 為了提高送貨速度則可以每次把車廂裝滿,減少送貨次數 車廂就是byte[]數組 批量送貨,減少磁盤讀寫 15 void (byte b[],int off,int len) :將指定的byte數組【從偏移量off開始的len個字節】寫入到目標文件。 批量寫入 16 17 void flush() :刷新此輸出流,并強制寫出所有緩沖中的字節 18 void close() : 關閉輸出流并釋放系統資源 19 20 * 21 */ 22 package cn.sxt.test; 23 24 import java.io.File; 25 import java.io.FileOutputStream; 26 import java.io.IOException; 27 import java.io.OutputStream; 28 29 public class Test_0329_OutputStream { 30 public static void main(String[] args) throws IOException { 31 //1、給出輸出流目的地(給出作業本)(與read()不同那個源文件必須存在,才可以被正確讀出,這里可不存在,幫你創建源文件) 32 File file=new File("編碼_GBK_輸出流.txt"); 33 //2、創建指向目的地的輸出流。參數:true:(前提是文件已存在)表示同意在文件末尾追加新字節數組, false:表示不同意,即覆蓋目的地文件的內容 34 OutputStream oStream=new FileOutputStream(file,true); 35 //3、讓輸出流把字節數組寫入目的地 36 String msg="I love you"; 37 byte datas[]=msg.getBytes(); 38 //ASCII碼 :范圍是十進制的 0-127 39 //byte:整形變量(8位,范圍十進制的-128-127) 字符串-->>字節存在名叫datas的數組 :編碼 40 //再次理解getBytes()方法: 此方法所做的工作就是英文字符(按GBK的方式,本電腦eclipse默認是GBK)進行編碼,然后把它們的 41 //十進制編碼存在datas數組中,GBK中文占3個字節,英文占1個字節.GBK兼容ACSII碼,所以英文字符的編碼就是它們的ACSII碼 42 //而且一個datas數組下標對應一個字節,對于英文1個下標存儲1個字符如:datas[0]=73對應英文字符'I' datas[1]=32 對應' '(空格) 43 //假設有中文字符則是datas[n-1][n][n+1]這3個連續的空間共同存儲一個中文字符(占3個字節)。這3個空間返回的分別是這個 44 //中文字符的編碼的(23-16位,15-8位,7-0位)的十進制數。 45 46 for (int i=0;i<datas.length ;i++) { 47 System.out.printf("datas[%d]=%d;",i,datas[i]); 48 //3-1:利用循環向txt文件中一個一個字節寫入 49 //oStream.write(datas[i]); 50 51 } 52 //3-2 一段一段字節去寫入 53 //oStream.write(datas);//把datas數組中的全部字符寫入目的文件 54 55 //3-3 寫入部分字節 往目的地的txt文件中寫了datas數組的部分字節(從下標2(字符'l')開始,長度為8的一段字節) 56 oStream.write(datas, 2, datas.length-2); 57 58 //4、關閉輸出流 59 oStream.close();; 60 } 61 62 }
?
【示例】利用輸入流和輸出流進行文件復制_不帶緩沖數組 (FileInputStream)
1 /* 2 *利用輸入流和輸出流完成文件的復制 3 * 輸入流(InputStream) 書本的知識輸入到大腦中,大腦要讀取(read)知識 4 * 輸出流(OutputStream) 大腦中的知識要寫出(write)到作業本上 5 * 1、為了減少對硬盤的讀寫次數,提高效率,通常設置緩存數組。相應地,讀取時使用的方法為:read(byte[] b) 6 * 寫入時的方法為:write(byte[ ] b, int off, int length)。 7 */ 8 package cn.sxt.test; 9 10 import java.io.File; 11 import java.io.FileInputStream; 12 import java.io.FileOutputStream; 13 import java.io.IOException; 14 import java.io.InputStream; 15 import java.io.OutputStream; 16 17 public class Test_0330_CopyFile { 18 public static void main(String[] args) throws Exception { 19 20 //copy("SongYi.jpg", "Song2.jpg"); 圖片也可復制,但是要注意設置緩沖數組的大小 21 copy("src.txt", "src_copy3.txt"); 22 } 23 24 25 static void copy(String src,String dest) throws IOException{ 26 //1、獲取源數據 27 File file =new File(src);//源文件 從這里讀取字節 28 File file2=new File(dest);//目標文件 往這里寫入字節 29 30 //2、選擇流 31 InputStream iStream=new FileInputStream(file);//輸入流 。從源文件(書本)輸入到程序中(大腦中) 32 OutputStream oStream=new FileOutputStream(file2);//輸出流。 從程序中(大腦中)輸出到目標文件(作業本)上.采用的是覆蓋,而不是追加 33 34 //3、選擇操作 35 /*把讀到數據存在butter數組從下標0開始的位置,每次存儲長度為數組的長度(也即一次就讀完)。若butter.length 改為4表示 36 *每次只讀取源文件的(從頭開始的)前4個字節,存在butter[0]--butter[3]中,至于源文件剩下的需要再次運行程序讀取或加個循環 37 *對于較大的文件(如圖片)可以加大緩沖數組的容量 38 */ 39 byte butter[]=new byte[1024];//緩沖數組,數組的大小為1024 。中轉站 大腦 40 41 /* //3-1:整體讀取寫入,每次都固定讀取1024個字節 42 iStream.read(butter); 43 oStream.write(butter);*/ 44 45 // 3-2 :可以選擇整體讀取或者部分讀入(即把butter.length的數值改低).這里起到效果是整體讀取與3-1是一個道理 46 iStream.read(butter,0,butter.length); 47 oStream.write(butter, 0, butter.length); 48 49 50 /*//可以具體看看讀取到的內容 詳細步驟 51 iStream.read(butter,0,butter.length); 52 String msg=new String(butter,0,butter.length);//字節-->>字符串:解碼 53 System.out.println(msg); 54 byte datas[]=msg.getBytes();//對讀取到的msg字符串進行編碼:字符串-->>字節 55 oStream.write(datas, 0, datas.length); */ 56 57 58 //4、關閉流 59 oStream.close(); 60 iStream.close(); 61 62 } 63 }
?【代碼示例】字節文件操作流_帶緩沖數組 (ButteredInputStream)大小為8192B(大小就是8KB,2^13次方,1KB=1024B,)
·
1 /** 2 * 學習 BufferedInputStream/BufferedOutputStream 緩沖字節流類 3 *復制文件 測試Java自帶的在緩沖數組的輸入輸出流 4 */ 5 6 package cn.sxt.test; 7 8 import java.io.BufferedInputStream; 9 import java.io.BufferedOutputStream; 10 import java.io.FileInputStream; 11 import java.io.FileOutputStream; 12 import java.io.IOException; 13 14 15 public class Test_0330_Buffered { 16 public static void main(String[] args) throws IOException { 17 /*File file=new File("poem.txt"); 18 InputStream iStream=new FileInputStream(file);*/ 19 //帶緩沖的輸入流 緩沖區為8KB 8192B (8192個字節) 20 FileInputStream file=new FileInputStream("poem.txt"); 21 BufferedInputStream iStream=new BufferedInputStream(file); 22 23 FileOutputStream file2=new FileOutputStream("poem2.txt"); 24 BufferedOutputStream oStream=new BufferedOutputStream(file2); 25 long b=System.currentTimeMillis();//獲取系統當前時間 26 int len; 27 while ( (len=iStream.read()) !=-1) { 28 oStream.write(len); //當調用read()或write()方法時 首先將讀寫的數據存入類內部定義好8KB的數組中,然后一次性 29 //讀寫到文件中,類似于前邊自己自定義的大小為1KB的數組,極大提高讀寫效率 30 } 31 long c=System.currentTimeMillis(); 32 System.out.println("共花費:"+(c-b)+"毫秒"); 33 iStream.close(); 34 oStream.close(); 35 36 37 //不帶緩存緩沖的 38 FileInputStream file3=new FileInputStream("poem.txt"); 39 FileOutputStream file4=new FileOutputStream("poem3.txt"); 40 41 long d=System.currentTimeMillis();//獲取系統當前時間 42 int length;//不帶緩沖區的,老辦法,讀取一個字節,往文件中寫一個字節。循環往復直到結束。速度很慢 43 while ( (length=file3.read()) !=-1) { 44 file4.write(length); 45 } 46 long e=System.currentTimeMillis(); 47 System.out.println("共花費:"+(e-b)+"毫秒"); //很明顯比帶緩沖區的花費時間多 48 file3.close(); 49 file4.close(); 50 51 52 } 53 54 }
?
轉載于:https://www.cnblogs.com/ID-qingxin/p/10623587.html
總結
以上是生活随笔為你收集整理的[19/03/30-星期六] IO技术_四大抽象类_ 字节流( 字节输入流 InputStream 、字符输出流 OutputStream )_(含字节文件缓冲流)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 复方樟脑乳膏治疗湿疹需要疗程使用吗 效果
- 下一篇: 修一个惠普的鼠标键盘和触碰面板多少钱?