1. 程式人生 > >Java的IO流與物件的序列化淺談

Java的IO流與物件的序列化淺談

今天再次回顧了一些關於java IO流的知識。雖然以前會點IO的方面的程式設計,但是還是知其然不知其所以然。

首先上一張IO流的主要家族圖吧。

    

    

該圖給出了IO流的具體分類和各類之間的繼承關係。其中還給出了各個類的使用場景和用途。

一、IO流的主流分類

    IO流主要分為位元組流和字元流。它們之間的區別就是:

1、讀寫的單位不同,位元組流是以位元組(8bit)為單位的。字元流是以字元為單位的,根據字元碼錶對映的字元,一次可能讀取多個位元組。

2、處理的物件不同。位元組流處理所有型別的資料,包括圖片、音視訊等。而字元流只能處理字元型的資料。

3、位元組流是直接傳輸的流通道,在進行流操作時是沒有緩衝區的。但是字元流在操作的時候會使用到緩衝區。這就是為什麼字元流的類例項都會有flush()

方法。

    然後針對位元組流和字元流會分成相應的輸入輸出流。

位元組流:InputStream輸入位元組流、OutputStream輸出位元組流。

字元流:Reader字元輸入流、Writer字元輸出流。 

二、檔案類的介紹和說明

java中表示檔案類的有FileRandomAccessFile類。而IO流的類主要是針對檔案類中的檔案內容來進行讀寫的操作的。

    1、File類表示檔案的本身,可以直接使用此類來完成檔案的各種操作。比如:建立、刪除、判斷是否為目錄等。

    2、RandomAccessFile類可以從指定的位置開始讀取資訊,主要是因為這個類中定義了檔案指標。但是這個類是要求檔案中各個資料的儲存的長度必須是固定的。

接下來舉一個經常會問到的例子:如何遍歷一個檔案目錄中的所用檔案??

         

程式碼如下:

package com.io;

import java.io.*;

public class listFile {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//1 新建一個File類的例項
		File file=new File("d:"+File.separator+"Xiaomi");
		//2 進行檔案目錄的列印
		print(file);
	}

	public static void print(File file) {
		// TODO Auto-generated method stub
		if(file!=null){//判斷檔案不為空
			if(file.isDirectory()){//判斷檔案是不是目錄
			   File[] fs=file.listFiles();//返回所有的子檔案
			       if(fs!=null){
			    	   //開始遍歷子檔案
			    	   for (int i = 0; i < fs.length; i++) {
			    		   		print(fs[i]);
			    	   		}
			       }
			}else{//如果不是目錄就列印檔案的路徑
				System.out.println(file);
			}
		}
	}

}

結果顯示:


三、輸入輸出流的介紹

    輸入輸出流主要分為位元組流和字元流。但是在傳輸中使用位元組流的操作會比較的多。InputStream輸入位元組流、OutputStream輸出位元組流、Reader字元輸入流、Writer字元輸出流它們都是抽象類,根據使用的子類不同輸入或輸出的位置會不同。

比如向對上面的File檔案類來進行操作時,我們應該會想到使用FileInputStreamFileOutputStream類。

JavaJDK中也提供了將位元組流轉換為字元流的類:InputStreamReader(InputStream)OutputStreamWriter(OutputStream)這兩個類。

使用ByteArrayInputStreamByteArrayOutputStream類是可以對記憶體進行輸入和輸出的。

線上程之間進行輸入和輸出時主要使用的是PipedOutputStreamPipedInputStream類。

    這裡注意一下,在日常的IO輸出時最好是使用列印流來進行輸出。即PrintWriterPrintStream類。這樣可以方便的列印各種型別的資料,說到底就是列印流中的print方法實現了對各種資料列印方法的過載。還有我們經常使用的System.out實際上就是一個PrintStream類。

-----------------------------------------------------*-------------------------------------------------------------------------

    當然對於這些IO輸入輸出類實際上我們是可以進行裝飾的。這就是FilterInputStreamFilterReader等類的作用,它們的子類就是對應的各種各樣的裝飾類。比如以 FilterOutputStream的子類是:BufferedOutputStream、 DataOutputStreamPrintStream

    BufferedOutputStream是可以直接向緩衝區寫入資料。該類實現緩衝的輸出流。通過設定這種輸出流,應用程式就可以將各個位元組寫入底層輸出流中,而不必針對每次位元組寫入呼叫底層系統。 

    DataOutputStream是資料輸出流,提供了與平臺無關的資料操作。資料輸出流允許應用程式以適當方式將基本 Java 資料型別寫入輸出流中。然後,應用程式可以使用資料輸入流將資料讀入。

    PrintStream 為其他輸出流添加了功能,使它們能夠方便地列印各種資料值表示形式。

注意這些經過裝飾類修飾的IO位元組流,有的會帶有緩衝區功能。所以也就會有flush()方法。 

    BufferedOutputStream為IO提供了帶有緩衝區的操作,一般開啟檔案進行寫入或讀取操作時,都會加上緩衝,這種流模式提高了IO的效能。從應用程式中把輸入放入檔案,相當於將一缸水倒入另一個缸中。

1>  FileOutputStream---->write方法相當於一滴一滴的把水轉移過去。

2>  DataOutputStream-->writeXXX方法會方便一些,相當於一瓢一瓢的把水轉移過去

3>  BufferedOutputStream-->write()方法會更方便一些,相當於一瓢一瓢先放入水桶中,在從桶中倒入缸中,效能提高了。


四、物件的序列化

什麼叫物件的序列化。實際上就是把一個物件變為二進位制的位元組資料流的一種方法。


    如果一個類想實現序列化只需要實現Serializable介面即可。接著我們是如何將這個類進行傳輸的。這時會有兩個位元組流:ObjectInputStreamObjectOutputStream(物件輸入輸出流)。我們要知道類的序列化序列的是屬性的內容,不會序列化方法的。如果我們使用transient關鍵字來修飾某個屬性,這就表示這個屬性是不會被序列化的。

為何要進行序列化呢.不進行序列化,我的程式不跑的好好的嗎?你想要什麼結果,我也能給解決不是.我想說確實是這樣,如果你的程式與網路無關,那很好你已經可以摒棄它了.
    那下面我來簡單分析下為何java需要進行序列化呢?
    首先我們要明白,序列化是做什麼作用的?java序列化:以特定的方式對類例項的瞬時狀態進行編碼儲存的一種操作。(可能不是很精確,咱不是搞學術的,看懂即可)。從此定義可以看出,序列化作用的物件是類的例項。對例項進行序列化,就是儲存例項當前在記憶體中的狀態。包括例項的每一個屬性的值和引用等。
    既然後序列化,便會有反序列化。反序列化的作用便是將序列化後的編碼解碼成類例項的瞬時狀態,申請等同的記憶體儲存該例項。
    從上述定義可以發現,序列化就是為了儲存java的類物件的狀態的。儲存這個狀態的作用主要用於不同jvm之間進行類例項間的共享。在ORMaping中的快取機制,進行快取同步時,便是常見的java序列化的應用之一。在進行遠端方法呼叫,遠端過程呼叫時,採用序列化物件的傳輸也是一種應用...當你想從一個jvm中呼叫另一個jvm的物件時,你就可以考慮使用序列化了。

    簡而言之:序列化的作用就是為了不同jvm之間共享例項物件的一種解決方案。由java提供此機制,效率之高,是其他解決方案無法比擬的。


五、新的IO(NIO)

  我們知道在檔案操作的時候,速度的提高是很重要的。速度的提高是來自於我們使用了更接近於作業系統執行I/O的方式:通道和緩衝器。


     這裡唯一直接與通道互動的緩衝器(即緩衝區)就是ByteBuffer。這是新的IO,主要是為了提升IO操作的速度的。建議有時間去看JDK中的描述。

     下面的程式碼演示三種類型的流的可寫、可讀的通道:

package com.io;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/*注意該方法只能測試英文字元。如果測試中文就會出現亂碼*/
public class GetChannels {
	private static final int BSIZE=1024;//用於後面設定位元組緩衝區的大小
	public static void main(String[] args) throws  Exception{
		// TODO Auto-generated method stub
		//寫一個檔案
		FileChannel fc=new FileOutputStream("date.txt").getChannel();//獲取與此檔案輸出流相關的唯一通道
		fc.write(ByteBuffer.wrap("my dear,".getBytes()));//注意是先獲取字串的位元組陣列,然後在將位元組陣列包裝到緩衝區中
		fc.close();//關閉通道
		
		//嘗試在檔案中新增內容
		fc=new RandomAccessFile("date.txt", "rw").getChannel();//重新獲取檔案的任意操作流的唯一通道
		fc.position(fc.size());//將檔案指標指向最末尾,這樣可以防止之前的字元被新的字元給覆蓋
		fc.write(ByteBuffer.wrap("my family".getBytes()));
		fc.close();
		
		//讀取檔案
		fc=new FileInputStream("date.txt").getChannel();
		ByteBuffer buff=ByteBuffer.allocate(BSIZE);//分配一個新的位元組緩衝區,大小為1k
		fc.read(buff);//將檔案內容讀取到位元組緩衝區buff中
		buff.flip();//為讀取位元組緩衝區做準備
		while(buff.hasRemaining())//位元組緩衝區是否還有位元組元素
			System.out.print((char)buff.get());//獲取位元組,並轉化為字元
		
		
	}

}

結果顯示:


注意這種使用方法是無法讀取中文字元的。會出現亂碼的。所以嘗試使用編碼的方式來解決:

package com.io;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

public class BufferToText {
	private static final int BSIZE=1024;
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		//寫入file中
		FileChannel fc=new FileOutputStream("date2.txt").getChannel();
		fc.write(ByteBuffer.wrap("my love我的愛".getBytes()));//將字元轉換為位元組陣列,在放入位元組緩衝器中。最後寫入到通道中
		fc.close();
		fc=new FileInputStream("date2.txt").getChannel();
		ByteBuffer buffer=ByteBuffer.allocate(BSIZE);//定義一個指定大小的位元組緩衝區
		fc.read(buffer);
		buffer.flip();
		//列印讀取到的位元組
		//System.out.print(buffer.asCharBuffer());//這種方法沒什麼用,會出現亂碼。
		
		//我們需要系統的指定預設的字符集
		buffer.rewind();
		String encoding =System.getProperty("file.encoding");//獲取檔案的位元組碼
		System.out.println("Decoding using:"+encoding+":"+Charset.forName(encoding).decode(buffer));
		
		//或者我們也可以使用編碼來向檔案中寫入字元
		fc=new FileOutputStream("date3.txt").getChannel();
		fc.write(ByteBuffer.wrap("我是一份大菠菜。".getBytes("UTF-16BE")));
		fc.close();
		
		//接下來我們進行讀檔案
		fc=new FileInputStream("date3.txt").getChannel();
		buffer.clear();
		fc.read(buffer);
		buffer.flip();
		System.out.print(buffer.asCharBuffer());
	}

}

結果顯示:


相關推薦

Java的IO物件序列

今天再次回顧了一些關於java IO流的知識。雖然以前會點IO的方面的程式設計,但是還是知其然不知其所以然。 首先上一張IO流的主要家族圖吧。           該圖給出了IO流的具體分類和各類之間的繼承關係。其中還給出了各個類的使用場景和用途。 一、IO流的主流分類

Java——Properties集合,Object序列序列,打印,commons-IO文件工具類

都是 oos times odi store buffer src object 所有 一、properties集合 集合對象Properties類,繼承Hashtable,實現Map接口,可以和IO對象結合使用,實現數據的持久存儲。 p { margin-bottom:

IO--序列序列

ng- 對象 style 完成 alt 完整 寫入 配置 let IO流--序列化流與反序列化流: 序列化流:把對象當做流一樣寫入到文本文件中 ObjectOutputSream(); 反序列化流:把文本文件中的流對象還原成對象ObjectInputSream

java ->IO_序列序列

set final found class文件 ati 技術分享 保存到文件 back 序列化對象 序列化流與反序列化流 用於從流中讀取對象的操作流 ObjectInputStream 稱為 反序列化流 用於向流中寫入對象的操作流 ObjectOutputStream

序列序列

序列化是把物件特性儲存到物理介質上,反序列化是把儲存在物理介質上的物件取出還原成物件。 能被序列化的物件所屬的類必須實現Serializable介面。 1、物件序列化流ObjectOutputStream 構造方法: ObjectOutputStream(OutputStream out):建立寫入指

IO(File類,IO的分類,位元組和字元,轉換,緩衝物件序列

1.File類 File類可以在程式中 操作檔案和目錄。File類是通過建立File類物件,在呼叫File類的物件來進行相關操作的。 示例: --------------------- 本文來自 dajiahuooo 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/

Java筆記-I/O物件序列

物件序列化流 物件序列化流基本介紹 使用工具:ObjectOutputStream,ObjectInputStream 介紹:將物件以檔案的形式儲存在硬碟中,使之能更方便的傳輸。 條件:必須實現Serializable介面(實現了這個介面,但

序列序列,列印,工具類commons-IO

1序列化流與反序列化流 用於從流中讀取物件的操作流 ObjectInputStream    稱為 反序列化流 用於向流中寫入物件的操作流 ObjectOutputStream   稱為 序列化流 特點:用於操作物件。可以將物件寫入到檔案中,也可以從檔案

java之IO序列序列

一.物件序列化流ObjectOutputStream   用於向流中寫入物件的操作流 ObjectOutputStream   稱為 序列化流 ObjectOutputStream 將 Java 物件的基本資料型別和圖形寫入 OutputStream。可以使用 Object

Properties類、序列序列

Properties類 Properties類介紹 特點: 1、Hashtable的子類,map集合中的方法都可以用。 2、該集合沒有泛型。鍵值都是字串。 3、它是一個可以持久化的屬性集。鍵值可以儲存到集合中,也可以儲存到持久化的裝置(硬碟、U盤、光碟)上。鍵值的來源也可以是持久化的裝置。 4、有和流

黑馬程式設計師 總結(二十)——I/O物件序列) .

------- android培訓、java培訓、期待與您交流! ---------- 操作物件的流物件(ObjectInputStream和ObjectOutputStream) 在Java程式執行過程中,通過I/O流可以將基本型別或String型別變數的值進行存貯和傳輸

Java IO詳解(六)------序列序列物件

1、什麼是序列化與反序列化? 序列化:指把堆記憶體中的 Java 物件資料,通過某種方式把物件儲存到磁碟檔案中或者傳遞給其他網路節點(在網路上傳輸)。這個過程稱為序列化。通俗來說就是將資料結構或物件轉換成二進位制串的過程   反序列化:把磁碟檔案中

java io詳解六:序列序列物件

1、什麼是序列化與反序列化?   序列化:指把堆記憶體中的 Java 物件資料,通過某種方式把物件儲存到磁碟檔案中或者傳遞給其他網路節點(在網路上傳輸)。這個過程稱為序列化。通俗來說就是將資料結構或物件轉換成二進位制串的過程   反序列化:把磁碟檔案中的物件資料或者把網路節點上的物件資料,恢

類初始物件例項

類的初始化和物件的例項化 類的初始化是指類和介面載入到方法區後,因某些原因的觸發,執行靜態變數初始化語句和靜態初始化塊中語句的過程,初始化語句的執行順序是由上往下的。 類的初始化語句由編譯器

C#中的序列序列

今天我利用這篇文章給大家講解一下C#中的序列化與反序列化。這兩個概念我們再開發中經常用到,但是我們絕大部分只用到了其中的一部分,剩下的部分很多開發人員並不清楚,甚至可以說是不知道。因此我希望通過這篇文章能讓大家對序列化和反序列化的知識有更進一步的掌握。廢話不多說,開始進入正題。 一、什麼是序列化/反序列化 &

Java核心類庫-IO-對象(實現序列序列

.get throws 反序 code row cts new java cep 使用對象流來完成序列化和反序列化操作:   ObjectOutputStream:通過writeObject()方法做序列化操作的   ObjectInputStream:通過readObje

Java IO-5 序列序列

str ride log getname file urn turn objects transient 建一個Person類 1 package demo05; 2 3 import java.io.Serializable; 4 5 public cla

Java基礎-IO對象之序列序列

span 作者 創作 style -s 反序列化 ont 對象 io流                 Java基礎-IO流對象之序列化與反序列化                                     作者:尹正傑 版權聲明:原創作品,謝絕轉載!否則將追究

java序列序列序列

package com.qianfeng.test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.

JavaSE——序列序列(深拷貝使用了該技術(克隆物件(原型模式)))

在最近學習Spring原始碼系列的時候,接觸到了一個設計模式——原型模式(資料內容相同,但是是兩個完全不同的物件例項) 原理就是實現介面重寫clone方法。如果單純的呼叫super.clone方法就屬於淺拷貝,只會拷貝8大基本資料型別和String型別。而Date和物件屬性就是引用的同一個物