IO流.專業流yu編碼表

以下介紹IO包中擴展功能的流對象:基本都是裝飾設計模式。

Java.io.outputstream.PrintStream打印流

1:提供了更多的功能,比如打印方法。可以直接打印任意類型的數據。

2:它有一個自動刷新機制,創建該對象,指定參數,對於指定方法可以自動刷新。

3:它使用的本機默認的字符編碼.

4:該流的print方法不拋出IOException。

 

構造函數。

PrintStream(File file)  :創建具有指定文件且不帶自動行刷新的新打印流。

PrintStream(File file, String csn) :創建具有指定文件名稱和字符集且不帶自動行刷新的新打印流。

PrintStream(OutputStream out) :創建新的打印流。

PrintStream(OutputStream out, boolean autoFlush) :創建新的打印流。

PrintStream(OutputStream out, boolean autoFlush, Stringencoding) :創建新的打印流。

PrintStream(String fileName) :創建具有指定文件名稱且不帶自動行刷新的新打印流。

PrintStream(String fileName, String csn)

 只有輸出目的爲 流的時候 才能夠設置 是否自動刷新 操作文件 則沒有設置自動刷新需要手動刷新

其println()的有功能是 在字符串後面加上換行符號  (能夠與Buffered的readLine()方法相呼應,TCP傳輸的細節)

PrintStream可以操作目的:1:File對象。2:字符串路徑。3:字節輸出流。

前兩個都JDK1.5版本纔出現。而且在操作文本文件時,可指定字符編碼了。

 

當目的是一個字節輸出流時,如果使用的println方法,可以在printStream對象上加入一個true參數。這樣對於println方法可以進行自動的刷新,而不是等待緩衝區滿了再刷新。最終print方法都將具體的數據轉成字符串,而且都對IO異常進行了內部處理。

--------------------------------------------------------

PrintWriter:是字符流的子類,可以直接操作字符數據,同時也可以指定具體的編碼。具備了PrintStream的特點同時,還有自身特點:

該對象的目的地有四個:1:File對象。2:字符串路徑。3:字節輸出流。4:字符輸出流。

 只有輸出目的爲 流的時候 才能夠設置 是否自動刷新 操作文件 則沒有設置自動刷新需要手動刷新

建議:開發時儘量使用PrintWriter

 

構造方法中(目的)直接操作文件的第二參數是編碼表。

(目的)直接操作輸出流的,第二參數是自動刷新。

 

//讀取鍵盤錄入將數據轉成大寫顯示在控制檯.

BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));//源:鍵盤輸入

//目的:把數據寫到文件中,還想自動刷新。

PrintWriter out = new PrintWriter(new FileWriter("out.txt"),true);//設置true後自動刷新

String line = null;
while((line=bufr.readLine())!=null){
    if("over".equals(line))
        break;
    out.println(line.toUpperCase());//轉大寫輸出
}
    //注意:System.in,System.out這兩個標準的輸入輸出流,在jvm啓動時已經存在了。隨時可以使用。當jvm結束了,這兩個流就結束了。但是,當使用了顯示的close方法關閉時,這兩個流在提前結束了。
out.close();
bufr.close();

**********************************************************************************************************************

SequenceInputStream:序列流,作用就是將多個讀取流合併成一個讀取流。實現數據合併。

表示其他輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達文件末尾,接着從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的文件末尾爲止,並 補上文件結束的標緻。

這樣做,可以更方便的操作多個讀取流,其實這個序列流內部會有一個有序的集合容器,用於存儲多個讀取流對象。

構造方法

SequenceInputStream(InputStream s1,InputStream s2) 和並兩個輸入流爲一 最簡單 

SequenceInputStream(Enumeration<? extendsInputStream> e)  喲要合併兩個以上流 涉及到集合枚舉

該對象的構造函數參數是枚舉,想要獲取枚舉,需要有Vector集合,但不高效。需用ArrayList,但ArrayList中沒有枚舉,只有自己去創建枚舉對象。

但是方法怎麼實現呢?因爲枚舉操作的是具體集合中的元素,所以無法具體實現,但是枚舉和迭代器是功能一樣的,所以,可以用迭代替代枚舉。

 

ArrayList<FileInputStream> a = new ArrayList<FileInputStream>();
		for (int i = 0; i < parts; i++) {
			fis = new FileInputStream(new File(path,(i+1)+".part"));
			System.out.println(i);
			a.add(fis);
		}
		final Iterator it = a.iterator();//變量it在局部位置的內部類被訪問 所以it必須爲final
		//Enumeration e = Collections.enumeration(a);  測試過不可以呀
		Enumeration e = new Enumeration(){
			@Override
			public boolean hasMoreElements() {
				// TODO Auto-generated method stub
				return it.hasNext();
			}
			@Override
			public Object nextElement() {
				// TODO Auto-generated method stub
				return it.next();
			}};
		SequenceInputStream ss = new SequenceInputStream(e);
		FileOutputStream fos =  new FileOutputStream(un);
		byte[] buf = new byte[1024*1024];
		int len = 0;
		while ((len=ss.read(buf))!=-1) {
			fos.write(buf, 0, len);
			fos.flush();
		}

合併原理:多個讀取流對應一個輸出流。

切割原理:一個讀取流對應多個輸出流。

點擊打開鏈接

切割大文件

FileInputStream fis = new FileInputStream("E:/1998.rmvb");
		FileOutputStream fos = new FileOutputStream("E:/1.part");
		byte[] by = new byte[1024*1024];//創建一個存儲大小爲1M 的字節數組
		int len = 0;
		int count=1;
		int i=0;
		while ((len = fis.read(by))!=-1)
		{	
			i++;
			if(i==101)
			{
				count++;
				fos = new FileOutputStream("E:/"+count+".part");
				i=0;
			}
				
			fos.write(by,0,len);//字節數組內有多少 寫多少  字節流不需要刷新即可把數據寫入目標文件
		}
		fos.close();//養成關流的好習慣
		fis.close();

類 ObjectOutputStream   實現了DataInput接口 能夠寫如完整的基本數據

 注意被寫入的對象需要實現Serializable

    構造方法

        ObjectOutputStream(OutputStreamout)  不可直接操作文件 FileInputStream是專門操作文件的字節流

          創建寫入指定OutputStream 的 ObjectOutputStream。

    常用方法

         void write(int val)  寫入一個字節。

         void writeInt(int val) 寫入一個 32 位的 int 值。

         void writeObject(Object obj) 將指定的對象寫入ObjectOutputStream。

類 ObjectInputStream

    構造方法

        ObjectInputStream(InputStreamin)

          創建從指定InputStream 讀取的 ObjectInputStream。

    常用方法

         int readInt() 讀取一個 32 位的 int 值。

         int read() 讀取數據字節。

         Object readObject() 從ObjectInputStream 讀取對象。

ObjectOutputStream存的文件 只能用ObjectInputStream來讀取

對象的序列化:目的:將一個具體的對象進行持久化,寫入到硬盤上。

Serializable:給類定義標記,用於啓動對象的序列化功能,可以強制讓指定類具備序列化功能,該接口中沒有成員,這是一個標記接口。這個標記接口用於給序列化類提供UID。這個uid是依據類中的成員的數字簽名進行運行獲取的,成員變動則UID變化。如果不需要自動獲取一個uid,可以在類中,手動指定一個名稱爲serialVersionUID id號,static final longserialVersionUID = 42L; 依據編譯器的不同,或者對信息的高度敏感性。最好每一個序列化的類都進行手動顯示的UID的指定。

注意靜態數據不能被序列化,因爲靜態數據不在堆內存中,是存儲在靜態方法區中,無法被序列化存到文件。

如何將非靜態的數據不進行序列化transient關鍵字修飾此變量即可。

****************************************************************************************************

RandomAccessFile:  直接繼承Object 實現DataInput,DataOutput能夠讀和寫 能操作基本數據類型

特點:

1:該對象即可讀取,又可寫入。

2:該對象中的定義了一個大型的byte數組,通過定義指針來操作這個數組。

3:可以通過該對象的getFilePointer()獲取指針的位置,通過seek()方法設置指針的位置。

4:該對象操作的源和目的必須是文件

5:其實該對象內部封裝了字節讀取流和字節寫入流。

注意:實現隨機訪問,最好是數據有規律。該類不算是IO體系中的子類,而是直接繼承自Object但是它是IO包中的成員,因爲它具備讀和寫功能,內部封裝了一個數組,而且通過指針對數組的元素進行操作,其實完成讀寫的原理就是內部封裝了字節輸入流和輸出流。

構造方法

      RandomAccessFile(File file, String mode)

          創建從中讀取和向其中寫入(可選)的隨機訪問文件流,該文件由 File 參數指定。

RandomAccessFile(String name, String mode)

          創建從中讀取和向其中寫入(可選)的隨機訪問文件流,該文件具有指定名稱。

通過構造函數可看出 該類只能操作文件, 而且操作文件還有模式:只讀r 讀寫 rw

如果模式爲只讀 r ,不會創建文件。會去讀取一個已存在的文件,如果該文件不存在,則會出現異常

如果模式爲 rw的話,當操作的文件不存在,會自動創建,如果存在不會覆蓋

常用方法

        long length()  返回此文件的長度。

        int read()  從此文件中讀取一個數據字節。

        int read(byte[] b,int off, int len)   將最多 len 個數據字節從此文件讀入 byte 數組。

        int read(byte[] b,int off, int len)  將最多 len 個數據字節從此文件讀入 byte 數組。

        讀取基本數據類型  readByte()  readChar() readFloat()  readDouble()  readBoolean()

        String readLine()   從此文件讀取文本的下一行。

        void seek(longpos)  此文件開頭開始測量的指針偏移量,在該位置發生下一個讀取或寫入操作。

        int skipBytes(intn)    嘗試跳過輸入的 n 個字節以丟棄跳過的字節。

        void write(byte[]b)  將 b.length 個字節從指定 byte 數組寫入到此文件,並從當前文件指針開始。

        void write(int b)  向此文件寫入低8位的int。

void writeInt(intv)  按四個字節將 int 寫入該文件,先寫高字節。

void writeLong(longv)  按八個字節將 long 寫入該文件,先寫高字節。

********************************************************************************************

管道流:管道讀取流和管道寫入流可以像管道一樣對接上,管道讀取流就可以讀取管道寫入流寫入的數據。

注意:需要加入多線程技術,因爲單線程,先執行read,會發生死鎖,而read方法是阻塞式的,沒有數據的read方法會讓線程等待。

類 PipedOutputStream

    構造方法

        PipedOutputStream(PipedInputStreamsnk)  創建連接到指定管道輸入流的管道輸出流。

    常用方法

PipedOutputStream(PipedInputStreamsnk)  創建連接到指定管道輸入流的管道輸出流。

        voidwrite(int b)        將指定 byte 寫入傳送的輸出流。

類 PipedInputStream

        PipedInputStream()  創建尚未連接的 PipedInputStream。

        PipedInputStream(PipedOutputStreamsrc)  創建 PipedInputStream,使其連接到管道輸出流 src。

        PipedInputStream(PipedOutputStreamsrc, int pipeSize)

          創建一個PipedInputStream,使其連接到管道輸出流 src,並對管道緩衝區使用指定的管道大小。

常用方法

        voidconnect(PipedOutputStream src)      使此管道輸入流連接到管道輸出流 src。

        int read()  讀取此管道輸入流中的下一個數據字節。

        int read(byte[] b,int off, int len)  將最多 len 個數據字節從此管道輸入流讀入 byte 數組。

        protected  void receive(int b)  接收數據字節。

 

**************************************************************************

ByteArrayInputStream源:內存  在構造的時候,需要接收數據源,而且數據源是內存中的一個字節數組

ByteArrayOutputStream目的:內存在構造的時候不要定義數據目的,因爲該對象中已經內部封裝了可變長度的字節數組,這就是數據目的地。

這兩個流對象不涉及底層資源調用,操作的都是內存中數組,並沒有使用系統資源,所以不需要close關閉。

 ByteArrayOutputStream 主要方法

        voidwriteTo(OutputStream out)

          將此 byte 數組輸出流的全部內容寫入到指定的輸出流參數中。

        String toString()

          使用平臺默認的字符集,通過解碼字節將緩衝區內容轉換爲字符串。

        int size()   返回緩衝區的當前大小。


直接操作字節數組就可以了,爲什麼還要把數組封裝到流對象中呢?因爲數組本身沒有方法,只有一個length屬性。爲了便於數組的操作,將數組進行封裝,對外提供方法操作數組中的元素。

對於數組元素操作無非兩種操作:設置(寫)和獲取(讀),而這兩操作正好對應流的讀寫操作。這兩個對象就是使用了流的讀寫思想來操作數組。

//創建源:

    ByteArrayInputStreambis = new ByteArrayInputStream("abcdef".getBytes());

    //創建目的:

    ByteArrayOutputStreambos = new ByteArrayOutputStream();

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

編碼表

常見的編碼表

ASCII:美國標準信息交換碼。

用一個字節的7位可以表示。

ISO8859-1:拉丁碼錶。歐洲碼錶

用一個字節的8位表示。

GB2312:中國的中文編碼表6000多字。兩字節表示而且兩字節的高位都是1兼容ASCII

GBK:中國的中文編碼表升級,融合了更多的中文文字符號,一中文兩字節。兩萬多

Unicode:國際標準碼,融合了多種文字。

所有文字都用兩個字節來表示,Java語言使用的就是unicode

UTF-8:最多用三個字節來表示一個字符。

 

在程序中所有的數據都是以流的方式進行傳輸或保存的,程序需要數據的時候要使用輸入流讀取數據,而當程序需要將一些數據保存起來的時候,就要使用輸出流完成。

程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件。


你好  utf-8 >>>  gbk      浣犲ソ

         gbk   >>>  utf-8   ???

可以用來判斷編碼是utf-8還是gbk

 

String s = "";

              byte[]b = s.getBytes();

              for(int i = 0; i < b.length; i++) {

                     System.out.print(b[i]+",");

輸出:-57,-82,-47,-89,-55,-83,

中文用兩字節表示而且兩字節的高位都是1即都是負數

 

字符流能不能用於對圖片的操作,是不可以的。

原因  用字符流賦值圖片的話 有可能無法打開 因爲 字符流按默認編碼表讀取數據字符流讀兩字節數據(單字符)就會去查編碼表返回中文字符 如果能查到編碼表

對應的中文字符 那麼讀取的兩字節數據不會變(編碼不變) 如果查不到 那麼就會去未知數據區域查編碼會改變所讀取的編碼 那麼數據就可能會產生變化

字節流 + 字符編碼 = 字符流

  字符流處理的單元爲2個字節的Unicode字符,分別操作字符、字符數組或字符串,而字節流處理單元爲1個字節,操作字節和字節數組。所以字符流是由Java虛擬機將字節轉化爲2個字節的Unicode字符爲單位的字符而成的,所以它對多國語言支持性比較好!如果是音頻文件、圖片、歌曲,就用字節流好點,如果是關係到中文(文本)的,用字符流好點 
     所有文件的儲存是都是字節(byte)的儲存,在磁盤上保留的並不是文件的字符而是先把字符編碼成字節,再儲存這些字節到磁盤。在讀取文件(特別是文本文件)時,也是一個字節一個字節地讀取以形成字節序列 


//爲什麼你好 gbk -> 編碼 -> iso8859-1 ->解碼 =亂碼 -> iso8859-1 -> 編碼 -> gbk ->解碼 =你好

//     你好 utf-8 -> 編碼 -> iso8859-1 ->解碼 =亂碼 -> iso8859-1 -> 編碼 -> utf-8 ->解碼 =你好

//     你好 utf-8 -> 編碼 -> gbk ->解碼 =亂碼 -> gbk -> 編碼 -> utf-8 ->解碼 =你好

//不可以??  你好 gbk -> 編碼 -> utf-8 ->解碼 =亂碼 -> utf-8 -> 編碼 -> gbk ->解碼 = 亂碼

 

 

原數據 編碼存入文件(文件中的是編碼後數據)  讀取通過對照同一編碼表 讀取 還原數據

原數據 編碼存入文件(文件中的是編碼後數據)  讀取通過對照另一個編碼表 讀取 當遇到的編碼字節數據 找不到對應的符號 那麼就會 拿着編碼 去 未知字符區查找 字符 得出二進制數據 原數據改變

 

原二進制數據 通過編碼表轉碼 的到編碼數據 gbk兩字節二進制數據 轉碼爲 兩字節編碼數據   utf-8 三字節原二進制數據 通過utf-8編碼表 轉碼爲三字節編碼數據

 

在 Java 中,“字符串”與“字節串”之間可以方便地按照指定編碼規則進行轉化:

byte[] b = "中文123".getBytes("GB2312");// 從字符串按照 GB2312 得到字節串

System.out.println(b.length); // 得到長度爲7個 (D6,D0,CE,C4,31,32,33)

Stringstr = newString(b,"GB2312");// 從字節串按照 GB2312 得到字符串

System.out.println("中文123".length()); // 得到長度爲5,因爲是5個字符

 

在 java.io.* 包裏面有很多類,其中,以“Stream”結尾的類都是用來操作“字節串”的類,以“Reader”,“Writer”結尾的類都是用來操作“字符串”的類。任何一個文件保存到硬盤上的時候,都是以字節爲單位保存的,當要把“字符串”保存到硬盤上的文本文件,必然要選擇一種編碼。

有兩種方法來指定編碼:

Stringstr = "中文123";

// 第一種辦法:先用指定編碼轉化成字節串,然後用 Stream 類寫入

OutputStream os =newFileOutputStream("1.txt");

byte[] b = str.getBytes("utf-8");

os.write(b);

os.close();

// 第二種辦法:構造指定編碼的 Writer 來寫入字符串

Writer ow=newOutputStreamWriter(newFileOutputStream("2.txt"),"utf-8");

ow.write(str);

ow.close();

// 最後得到的 1.txt 和 2.txt 都是 9 個字節。(漢字在 utf-8編碼規則中佔3字節

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章