1. 程式人生 > >黑馬程式設計師 總結(二十)——I/O流(物件序列化) .

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

------- android培訓java培訓、期待與您交流! ----------

操作物件的流物件(ObjectInputStream和ObjectOutputStream)

在Java程式執行過程中,通過I/O流可以將基本型別或String型別變數的值進行存貯和傳輸。那麼,物件能否持久的存貯在計算機上呢?將Java程式中的物件儲存在外村中,稱為物件的持久化。物件持久化的關鍵是將它的狀態以一種序列格式表示出來,以便以後讀該物件時,能將其重構出來。因此,在Java中,物件序列化是指將物件寫入位元組流以實現物件的永續性,而在需要時又可以從位元組流中恢復物件的過程。物件序列化的主要任務是將物件資訊以二進位制流的形式輸出。如果物件的屬性又引用其他流物件,則遞迴序列化所有被引用的物件,從而建立一個完整的序列化流。

1、物件序列化的方法

物件序列化技術主要有兩個方面的內容:

一是如何使用類ObjectInputStream和ObjectOutputStream實現物件的序列化;

二是如何定義類,使其物件可以被序列化。

2、ObjectOutputStream類和ObjectInputStream

ObjectOutputStream 將 Java 物件的基本資料型別和圖形寫入 OutputStream。可以使用 ObjectInputStream 讀取(重構)物件。通過在流中使用檔案可以實現物件的持久儲存。如果流是網路套接字流,則可以在另一臺主機上或另一個程序中重構物件。

通過JavaAPI文件可知,在構造ObjectOutputStream時ObjectOutputStream(OutputStream out),往裡傳入一個位元組輸出流。以便將物件存入到外存。

1、ObjectOutputStream實現將物件序列化

在ObjectOutputStream中提供了writeObject()方法將物件寫入流中。該方法的定義如下:

public final void writeObject(Object obj) throws IOException.

當物件不可被序列化時,則writeObject()方法就會丟擲NotSerializableException型別異常

2、ObjectInputStream將序列化的物件讀到記憶體中

public final Object readObject()throws IOException,ClassNotFoundException   將示例話的物件讀取。

3、如何定義類,該類的物件才能被序列化

1、只有類實現了Serializable介面,其物件才可以被序列化。此介面是一個標記介面。當一個類在實現該介面時,未實現此介面的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子型別本身都是可序列化的。序列化介面沒有方法或欄位,僅用於標識可序列化的語義。

2、當類實現Serializable介面時,該類就自動生成一個序列化編號,該編號是根據類裡面定義的字元生成的,所以增加類的屬性或者刪除類的屬性都會使該類的序列號發生改變。如果儲存在外存中的物件的序列號和物件的序列號不匹配,則不能載入存在外存中的例項化物件資料。

3、為了使物件的序列號不隨類的屬性改變而改變,我們在實現Serializeble介面後,可以手動的給該物件指定一個序列號。方法是在鬼物件內加入一句   static final long serialVersionUID = **L

4、靜態的成員屬性不能被序列化,被trasizent關鍵字修飾的屬性也不能被序列化。被trasizent修飾的屬性,該屬性只在對記憶體中存在,而不能例項化到檔案中。

4、物件序列化的演示示例:

1、建立一個可以被序列化的類

//定義一個用於序列化化的物件
package com.itcast;

import java.io.Serializable;

public class Person implements Serializable{
	static final long serialVersionUID = 01L;
	private String name;
	private int age;
	private String id;
	
	Person(String name,int age){
		 this.name =name;
		this.age = age;
	}

	Person(String name,int age,String id){
		this(name,age);
		this.id = id;
	}
	public String toString(){
		return ("name:"+name+"-------age:"+age+"-----id:"+id);
	}

}

2、將該物件序列化

package com.itcast;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectStreamDemo {
	public static void main(String[] args)throws Exception{
		objectout();
		
	}
	public static void objectout()throws IOException{
		FileOutputStream fileout = new FileOutputStream("d:\\seri.ser");
		ObjectOutputStream objout = new ObjectOutputStream(fileout);
		
		objout.writeObject(new Person("Zhang,hm",23));
		objout.close();
	}
}

3、將序列化的物件讀到記憶體

package com.itcast;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectStreamDemo {
	public static void main(String[] args)throws Exception{
		objectin();
	}
	
	public static void objectin()throws Exception{
		FileInputStream filein = new FileInputStream("d:\\seri.ser");
		ObjectInputStream objin = new ObjectInputStream(filein);
		System.out.println(objin.readObject());
	}

}

管道流(PipedInputStream和PipedOutputStream)          所謂管道流就是將一個程式的輸出作為另一個程式的輸入的通道。JavaAPI提供了面向位元組的管道流PipedInputStream/PipedOutputStream和麵向字元的管道流PipedReader/PipedWriter,這兩種流的用法都很相似,都可以提供兩個執行緒之間的資料通訊通道。

管道輸入流應該連線到管道輸出流;管道輸入流提供要寫入管道輸出流的所有資料位元組。通常,資料由某個執行緒從PipedInputStream 物件讀取,並由其他執行緒將其寫入到相應的PipedOutputStream。不建議對這兩個物件嘗試使用單個執行緒,因為這樣可能死鎖執行緒。管道輸入流包含一個緩衝區,可在緩衝區限定的範圍內將讀操作和寫操作分離開。

示例:

將寫進管道輸出流的資料,通過管道輸入流讀取出來。

import java.io.*;

class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()
	{
		try
		{
			byte[] buf = new byte[1024];

			System.out.println("讀取前。。沒有資料阻塞");
			int len = in.read(buf);
			System.out.println("讀到資料。。阻塞結束");



			String s= new String(buf,0,len);

			System.out.println(s);

			in.close();

		}
		catch (IOException e)
		{
			throw new RuntimeException("管道讀取流失敗");
		}
	}
}

class Write implements Runnable
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			System.out.println("開始寫入資料,等待6秒後。");
			Thread.sleep(6000);
			out.write("piped lai la".getBytes());
			out.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("管道輸出流失敗");
		}
	}
}

class  PipedStreamDemo
{
	public static void main(String[] args) throws IOException
	{

		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		out.connect(in);

		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}


隨機讀寫檔案RandomAccessFile 前面我們所學習的Java流I/O 都是順序訪問流,即流中的資料必須是按順序進行讀寫的。Java還提供了一個功能強大的隨機存取檔案類RandomAccessFile,它可以對檔案隨機讀/寫操作。 該類不算是IO體系中的子類,而是直接整合Object。但是他是IO包中的成員,因為它具備讀和寫的功能。在RandomAccessFile能完成讀寫的原理是內部封裝了位元組輸入流和位元組輸出流。該物件只能操作檔案。 1、建立RandomAccessFile物件
用RandomAccessFile實現檔案隨機讀/寫的原理是將檔案看作位元組資料,並用檔案指標指示檔案當前的位置。當建立RandomAccessFile類的例項後,檔案指標指向檔案的頭部,當讀/寫n個位元組數後,檔案指標也會移動n個位元組,檔案指標的位置即下一次讀/寫的位置。由於Java中每種基本資料型別資料的長度是固定的,所以可以通過設定檔案指標的位置實現對檔案內容的讀寫。 RandomeAccessFile物件在建立的時候,如果在指定目錄下沒有該檔案則,建立該檔案。如果存在,就直接操作該檔案。 1、RandomAccessFile的構造方法:
public RandomAccessFile(String name,String mode) public RandomAccessFile(File file,String mode) 在第一個建構函式中 String name中的name表示以字串表示的路徑以及檔名,String mode表示該RandomAccessFile物件的模式:
r——只讀  w——只寫 rw——讀寫

2、RandomAccessFile物件的寫入和讀出

1、RandomAccessFile物件通過write(**)方法可以直接向對應的檔案中寫入 byte[]、以及指定byte[]的起始位置和結束位置將指定的區間的資料寫入、int。

注意:當通過write(**)向物件中寫入int型別的資料的時候,寫入檔案的僅僅是該資料的低八位。

2、通過Writer基本資料型別(基本資料型別  data):通過這些方法可以自動的將基本資料型別寫入檔案,如 writeInt( int 78)此時就會向檔案中寫入該基本型別的全部位元組數。

在讀出這些基本型別資料的時候,也必須呼叫其獨有的讀取方法。如讀取int型別資料:用readInt()方法

3、如果寫入的資料是字串則必須通過字串的getBytes()方法,將此字串轉換成字元陣列,讓後才能寫入。並且通過此方法將字串寫入檔案後,就算檔案是txt型別的檔案,也不能用readLine方法去讀取。readLine()方法只能用來讀取文字檔案。

3、RandomAccessFile物件的操作

RandomAccessFile通過對檔案指標的設定,就可以實現對檔案的隨機讀寫。下面是對指標的操作方法;

1、public long getFilePointer();   返回當前指標的位置。

2、public void seek(long pos);  將檔案指標設定到pos位置。

3、pubic void skipBytes(int n);  指標從當前位置向後跳n個位元組

4、RandomAccessFile物件所涉及的異常。

1、讀取和寫入(與流相關的操作)的時候如果失敗則丟擲IOException。

2、public byte[] read(byte[] b):如果由於檔案結束之外的某種原因不能讀取第一個位元組丟擲IOException

如果bnull,則丟擲NullPointerException異常

3、如果要讀取5個位元組,讀取的內容小於5個位元組則就會丟擲EOFException異常。

5、程式碼示例:

將指定的人的姓名和年齡按照指定的序號存進檔案,然後通過序號將該序號下人的姓名和年齡讀出

package com.itcast;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		writer("楊  郎",78,1);
		writer("成  四",67,2);
		writer("楊  柳",53,3);
		writer("李  明",33,4);
		
		reader(1);
		reader(3);
		reader(4);
	}/**
	將指定的人年齡存入指定的序號
	@param name 接收人的姓名
	@param age  接收人的年齡
	@param num  接收存貯的序號
	*/
	public static void writer(String name,int age,int num)throws IOException,FileNotFoundException{
		RandomAccessFile raf = new RandomAccessFile("d:\\raf.txt","rw");
		raf.seek((num-1)*10);
		byte[] names = new byte[6];
		names = name.getBytes();
		
		
		raf.write(names);
		raf.writeInt(age);

		raf.close();
	}/**
	將指定序號的人物的姓名和年齡輸出
	@param num 接收序號
	*/
	public static void reader(int num)throws IOException{
		RandomAccessFile raf = new RandomAccessFile("d:\\raf.txt","r");
		byte[] buf = new byte[6];
		raf.seek((num-1)*10);
		raf.read(buf);
		
		
		String name = new String(buf);
		int age = raf.readInt();
		System.out.println(name+" age is:"+age);
		
	} 
}


操作基本資料型別的流物件 (DataInputStreamDataOutputStream     用於操作基本的資料型別。該類是一個功能類,所以在建立該類的物件的時候應該要有被拓展的流物件。即構造時必須向裡面傳入一個相應的輸入或者輸出流。 1、基本資料型別的寫入:
通過writeInt(int num)、writeBoolean(boolean bl)……等,通過API文件可知,我們可以通過這些方法可以將這些型別的資料完整的寫入到檔案中,但是寫入檔案僅僅是資料儲存,被記事本開啟之後不能被識別。

2、資料的讀取:

通過該資料型別的讀取方式,從檔案中讀取這些資料。在讀取之前還是先得建立FileInputStream流物件與之關聯。並且讀取的順序必須和寫入的順序一樣。

3、特殊方法writeUTF(String str)和readUTF()

writeUTF(String str)以與機器無關方式使用UTF-8修改版格式編碼將一個字串寫入基礎輸出流。只能用對應的readUTF()方法讀取出來。

4、程式碼示例:

import java.io.*;
class DataStreamDemo 
{
	public static void main(String[] args) throws IOException
	{
		writeData();
		readData();

		writeUTFDemo();
		readUTFDemo();

	}
	public static void readUTFDemo()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));

		String s = dis.readUTF();

		System.out.println(s);
		dis.close();
	}



	public static void writeUTFDemo()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));

		dos.writeUTF("你好");

		dos.close();
	}

	public static void readData()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

		int num = dis.readInt();
		boolean b = dis.readBoolean();
		double d = dis.readDouble();

		System.out.println("num="+num);
		System.out.println("b="+b);
		System.out.println("d="+d);

		dis.close();
	}
	public static void writeData()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

		dos.writeInt(234);
		dos.writeBoolean(true);
		dos.writeDouble(9887.543);

		dos.close();

		ObjectOutputStream oos = null;
		oos.writeObject(new O());
	
	}
}
字元編碼 1、常見的編碼表
ASCII:美國標準資訊交換碼,用一個位元組的7位表示。 ISO8859-1:拉丁碼錶。歐洲碼錶,用一個位元組8位表示。 GB2312:中國的中文編碼表 GBK:中文的編碼表升級,融合了更多中文和字元。 Unicode:國際標準碼,融合了多種文字。所有文字都用兩個位元組來表示,Java語言使用的是Unicode UTF-8:最多用三個位元組來表示一個字元

2、中文字元編碼:

在String類中有getBytes(String charsetName);返回通過該字符集編碼的字元編碼 儲存在byte[]中。

getbytes(),返回系統預設字符集對該字串的編碼,

3、將獲取的編碼解碼:

通過new String(byte[] n,String charsetName)就可以將此編碼解碼。

如果未正確解碼,則將解碼後的字元按原字符集編碼,然後再進行解碼。

相關推薦

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

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

黑馬程式設計師 總結——I/O

------- android培訓、java培訓、期待與您交流! ---------- I/O流 程式在執行時通常要和外部進行互動,從外部讀取資料或向外部裝置傳送資料,這就是所謂的I/O。Java使用抽象概念——流(stream)來描述程式與資料傳送或者接收的通道。I/O流

Java 之路 () -- Java I/OBIO、檔案、資料、如何選擇I/O、典型用例

前言 Java 的 I/O 類庫使用 流 這個抽象概念,代表任何有能力產出資料的資料來源物件或者是有能力接收資料的接收端物件。流 遮蔽了實際的 I/O 裝置中處理資料的細節。 資料流是一串連續不斷的資料的集合,簡單理解的話,我們可以把 Java 資料流當作是

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

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

黑馬程式設計師----基礎學習第

                                                                                     ------- android培訓、java培訓、期待與您交流! ----------         

程式設計師必會的步快速學習法附書單

![](https://images.cnblogs.com/cnblogs_com/binfun/1921791/o_210124095548p1.jpg) 本文對《軟技能:程式碼之外的生存指南》書中的“十步學習法”展開討論,該書作者是John Z. Sonmez,一名程式設計師,書中有很多面試、專業等建

python全棧開發【第篇】Python常用模塊時間、random、os、sys和序列

utc時間 用戶 這也 文件名 password 如何 json字符串 並且 持久 一、time模塊 表示時間的三種方式:   時間戳:數字(計算機能認識的)   時間字符串:t=‘2012-12-12‘   結構化時間:time.struct_time(tm_year=2

從零開始之驅動發開、linux驅動、linux裝置驅動中的併發控制

本文參考自宋寶華老師的《linux驅動開發詳解》 併發(Concurrency) 指的是多個執行單元同時、 並行被執行, 而併發的執行單元對共享資源(硬體資源和軟體上的全域性變數、 靜態變數等) 的訪問則很容易導致競態(Race Conditions)   只要併發的

程式設計師的奮鬥史 八 寒門再難出貴子

                        文/溫國兵        相信讀者大都看過這篇文章。如果沒看過趕緊去天涯論壇看看或者關注鬼腳七閱讀吧。天涯原文:寒門再難出貴子(修改版);知乎相關話題:「這個時代 寒門再難出貴子」如何看待?         這篇文章最早是永樂大帝最早在天涯論壇上發的,我是從鬼腳

C# 五、匿名型別與物件初始附帶:類初始

匿名型別提供了一種方便的方法,可用來將一組只讀屬性封裝到單個物件中,而無需首先顯式定義一個型別。 型別名由編譯器生成,並且不能在原始碼級使用。 每個屬性的型別由編譯器推斷。 可通過使用new運算子和物件初始值建立匿名型別。 匿名型別包含一個或多個公共只讀屬性。 包含

黑馬程式設計師--- 學習筆記(第四天)

——————————ASP.Net+Android+IOS開發、.Net培訓、期待與您交流!—————————— 集合: 集合是一種容器.是可變長度的,可以儲存不同型別的物件. 集合框架: Collection|--List   |--ArrayList   |--Link

遠端服務:Java 物件序列和反序列

在遠端方法呼叫 RMI 學習的過程中,涉及到一個概念,序列化,本文進行詳述。 Java 物件的序列化和反序列化 的兩種應用場景 有時候需要將 Java 物件儲存永久儲存,比如儲存到檔

JAVA-初步認識-I/O字節流-FileWriter-異常處理

span 指針 出現 ima bsp file 字節 創建 出現異常 一. 通用換行的知識點是在哪兒介紹的?新建了FileWriter就有異常。 將拋出異常語句去掉後,後面幾句話都會出現異常。 紅色波浪線全部出現就是有異常。 文件找不到異常可以理解,為什麽還有

JAVA-初步認識-I/O字節流-FileReader-讀取方式1

結果 奇怪 字節 進行 read file -s 聯想 子類 一. 寫完之後,要進行讀取。現在講解的對象從FileWriter變為了FileReader,從輸出為了輸入。 對於IO流的講解,始終是圍繞著字符流來的,立足點也是字符流中的兩個具體的子類對象。 Reader對象的

JAVA-初步認識-I/O字符-緩沖區-解釋

bsp 內部 inf .com 分享 png 緩沖區 com gpo 一. 說完了字符流操作文件的基本對象應用以外, 我以為緩沖區是流對象自己內部,而不是中轉站buf。 這裏就是介紹一下緩沖區,作為一個中轉的地方。緩沖區更為深入的用法,還不會,理解還不夠。JAVA-初步

JAVA-初步認識-I/O字符-緩沖區-BufferWriter

講解 技術分享 字符 alt spa 技術 span 分類 為什麽 一. 對於緩沖區,也進行了分類,緩沖讀和緩沖寫。現在講解緩沖寫。 為什麽會有BufferWriter這樣的對象存在,就是將之前的ch,buf之類的東西和流對象結合起來,使它們成為一個整體。 將緩沖的功能融

JAVA-初步認識-I/O字符-緩沖區-BufferedReader-ReadLine方法原理

操作 nbsp 分享 硬盤 image ade mage 認識 adl 一. 如果按照之前的說法,緩沖區就是數組的話,那麽寫bufr.read(buf)就不能理解。這句話只能看成bufr這個緩沖區對象,采用read方法,將數據讀到buf中,而不是緩沖區對象bufr讀取

java基礎之I/O-------轉換

一.轉換流的概念: 轉換流即包裝流,可以使位元組流轉換成字元流,也可以字元流轉成位元組流。         二.位元組流轉字元流:                    1.InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的 charset

I/O3

三、字元流 1.Reader和Writer抽象類    位元組流提供處理任何型別輸入/輸出操作的足夠功能,但不能直接操作Unicode字元,因而需要字元流(主要用於檢視檔案內容),字元流層次結構的頂層是Reader和Writer抽象類。 (1)Reader是定義Java

Java內容梳理18API學習6I/O

目錄: 1、I/O流的分類 2、常用的I/O流 3、物件的序列化和反序列化 4、物件克隆 5、圖片操作 1、I/O流的分類 (1)介紹 流說明了Java中讀寫資料的方式: 順序讀寫資料:從左到右,從上到下依此讀取資料 資料的流動方向:單向 參照物:程式