1. 程式人生 > >大資料java篇——IO流

大資料java篇——IO流

IO流常用基類

IO流按操作資料分為:位元組流+字元流

  1. 位元組流的抽象基類:InputStream,OutputStream
  2. 字元流的抽象基類:Reader,Writer
  3. 由這四個類派生出來的子類名稱都是以其父類名作為子類名的字尾。如:InputStream的子類FileInputStream,Reader的子類FileReader。
  4. 寫的時候用輸出流,讀的時候用輸入流。

FileWriter/FileReader

1.檔案寫入

字元流建立檔案過程:

1.建立流物件,建立資料存放檔案(用try-catch包住或者在宣告主函式的時候丟擲異常)

FileWriter fw = new FileWriter("d:/aa.txt");

2.呼叫流物件的寫入方法,將資料寫入流

fw.write("Hello world");

write方法:

public void write(int c) 寫入單個字元
public void write(char[] cbuf) 把字元陣列寫入
public abstract void write(char[] cbuf,int off,int len) 寫入字元陣列的某一部分
public void write(String str) 寫入字串
public void write(String str,int off,int len) 寫入字串的某一部分

3.關閉流資源,並將流中的資料清空到檔案中

fw.close();
package IO;

import java.io.FileWriter;
import java.io.IOException;

public class App {

	public static void main(String[] args) {
		try {
			FileWriter fw = new FileWriter("d:/aa.txt");
			fw.write("Hello world");
			fw.close();
			System.out.println("Over");
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

考慮健壯性

package IO;

import java.io.FileWriter;
import java.io.IOException;

public class App {

	public static void main(String[] args) {
		FileWriter fw = null;
		try {
			fw = new FileWriter("d:/aa.txt");
			fw.write("Hello world");
			
			System.out.println("Over");
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally{
			//釋放資源
			try {
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

}
package IO;

import java.io.FileWriter;
import java.io.IOException;

public class App {

	public static void main(String[] args) {
		FileWriter fw = null;
		try {
			//預設是覆蓋模式(false),改為true變為追加
			fw = new FileWriter("d:/aa.txt,",true);
			fw.write("Hello world\r\n");
			fw.write("How are you\r\n"); // 回車換行
			fw.write("我懂了\r\n");
			System.out.println("Over");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 釋放資源
			try {
				fw.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

}

2.檔案讀取

字元流讀取過程:

1.建立一個流物件,將已經存在的檔案載入進流

FileReader fr = new FileReader("aa.txt")    //路徑+檔名

檔案路徑可以用"/"或者"\\"表示

2.建立一個臨時存放資料的陣列(也叫緩衝區)

char[] ch = new char[1024];

3.呼叫流物件的讀取方法將流中的資料讀入到陣列中

fr.read(ch);

read() 讀取一個單一字元,返回所讀取的字元,如果流已經到達了檔案尾,則返回-1。

read(char[] cbuf) 將字元讀入陣列,cbuf為目標緩衝區,返回的是讀取的字元數

package IO;

import java.io.FileReader;

public class FileReaderDemo {

	public static void main(String[] args) throws Exception {
		//一個一個字元讀
		FileReader fr = new FileReader("d:/aa.txt");
		int i =0;
		while( (i = fr.read()) != -1){						//read()讀取一個單一字元,返回所讀取的字元,如果流已經到達了檔案尾,則返回-1。
			System.out.print((char)i);
		}  
		fr.close();
		
		//使用char[]緩衝區讀取檔案
		System.out.println("--------------------------");
		int len = 0;
		fr = new FileReader("d:/aa.txt");					//第九行賦值的fr其指標已經到了尾端,因此需要重新new一下
		char[] buf = new char[10];
		while((len = fr.read(buf)) != -1){
			System.out.print(new String(buf,0,len));
		}
		fr.close();

	}

}

mark (int readAheadLimit) 標記流中的當前位置。對 reset() 的後續呼叫將嘗試將該流重新定位到此點。並不是所有的字元輸入                                                     流都支援 mark() 操作。

reset () 重置該流。如果已標記該流,則嘗試在該標記處重新定位該流。並不是所有的字元輸入流都支援 reset() 操作.

skip (long n) 跳過字元。

但FileReader 不支援mark和reset

3. 利實現檔案的複製

package IO;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyFileDemo {

	public static void main(String[] args) {
		String srcfile = "d:/aa.txt";
		String targfile = "d:/bb.txt";
		FileReader reader = null;
		FileWriter writer = null;
		try {
			reader = new FileReader(srcfile);
			writer = new FileWriter(targfile);
			//定義字元緩衝區
			char[] buf = new char[1024];
			int len = 0;
			while((len = reader.read(buf)) != -1){
				writer.write(buf, 0, len);
			}
			System.out.println("over");
			
		} 
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally{
			try {
				reader.close();
				writer.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}

}

BufferedWriter/BufferedReader

字元流緩衝區的出現提高了對資料的讀寫效率,對應類有BufferedWriter和BufferedReader,緩衝區要結合流才可以使用。

BufferedWriter/BufferedReader 支援 mark() 和 reset()

1.BufferedWriter

FileWriter沒有緩衝區功能,本身沒有新增任何功能,繼承OutputStreamWriter。

等級樹結構: Object ——> Writer ——> OutputStreamWriter ——> FileWriter

BufferedWriter對Writer進行包裝,裡面定義緩衝區,提供寫入單個字元、char[]、String的效率

等級樹結構:Object ——> Writer ——> BufferedWriter

flushBuffer() 清理緩衝區,將緩衝區資料寫入到目的地。

BufferedWriter 的 close() 方法中包含 flushBuffer() 方法。

package IO;

import java.io.BufferedWriter;
import java.io.FileWriter;

public class BufferedWriterDemo {

	public static void main(String[] args) throws Exception {
		//非緩衝
		FileWriter writer = new FileWriter("d:/a.txt");
		//緩衝
		BufferedWriter bufWriter = new BufferedWriter(new FileWriter("d:/b.txt")); //將FileWriter包裝
		
		/***********************非緩衝區writer操作************************/
		//最大次數
		int max = 1000000;
		//開始時間
		long startTime = System.currentTimeMillis();
		for(int i =0 ; i<max ; i++){
			writer.write("a");
		}
		writer.close();
		//結束時間
		long endTime = System.currentTimeMillis();
		System.out.println("writer over:花了" + (endTime-startTime) + "毫秒");
		
		/********************緩衝區writer操作************************/
		startTime = System.currentTimeMillis();
		for(int i =0 ; i<max ; i++){
			bufWriter.write("a");
		}
		bufWriter.close();
		//結束時間
		endTime = System.currentTimeMillis();
		System.out.println("bufWriter over:花了" + (endTime-startTime) + "毫秒");

	}

}

但需要注意的是,並不是有緩衝區速度就快,寫入速度和緩衝區容量以及要寫入的大小有很大關係。

2.BufferedReader

FileReader

等級樹結構:Object ——> Reader ——> InputStreamReader ——> FileReader

BufferedReader

等級樹結構:Object ——> Reader ——> BufferedReader ——> LineNumberReader

BufferedReader 方法:

1.readLine() 讀取文字行,無論何時讀取行結束符,當前行號都將加 1。返回包含行內容的字串,不包括任何行結束符,如果已    到達流的末尾,則返回 null;

package IO;

import java.io.BufferedReader;
import java.io.FileReader;

public class BufferedReaderDemo {

	public static void main(String[] args) throws Exception {
		BufferedReader bufReader = new BufferedReader(new FileReader("d:/a.txt"));
		String line = null;
		while((line = bufReader.readLine()) != null){
			System.out.println(line);
		}
		System.out.println("over");
		bufReader.close();

	}

}

3.LineNumberReader

繼承了BufferedReader,中有輸出行號的方法 getLineNumber() ;

package IO;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.LineNumberReader;

public class BufferedReaderDemo {

	public static void main(String[] args) throws Exception {
		BufferedReader bufReader = new BufferedReader(new FileReader("d:/a.txt"));
		String line = null;
		while((line = bufReader.readLine()) != null){
			System.out.println(line);
		}
		System.out.println("over");
		bufReader.close();
		
		/*
		 * 使用LineNumberReader讀取檔案行號
		 * 答應輸出 行號+內容
		 */
		LineNumberReader lineNumReader = new LineNumberReader(new FileReader("d:/a.txt"));
		while((line = lineNumReader.readLine()) != null){
			int lineNo = lineNumReader.getLineNumber();
			System.out.println(lineNo + "." + line);
		}
		lineNumReader.close();

	}

}

FileInputStream/FileOutputStream

OutputStream:

此抽象類是表示輸出位元組流的所有類的超類。輸出流接受輸出位元組並將這些位元組傳送到某個接收器。

OutputStream方法:

1.write(byte[] b) 將 b.length 個位元組從指定的byte陣列寫入此輸出流。

2.write(byte[] b,int off,int len) 將指定 byte 陣列中從偏移量 off 開始的 len 個位元組寫入此輸出流

3.write(int b) 將指定的位元組寫入此輸出流

4.flush() 重新整理此輸出流並強制寫出所有緩衝的輸出位元組

5.close() 關閉此輸出流並釋放與此流有關的所有系統資源

FileOutputStream繼承了OutputStream

FileOutputStream的構造方法中有

 建立一個向具有指定 name 的檔案中寫入資料的輸出檔案流。如果第二個引數為 true,則將位元組寫入檔案末尾處,而不是寫入檔案開始處。

package IO;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class FileOutputStreamDemo {

	public static void main(String[] args) throws Exception {
		/*
		 * 利用FileOutputStream和FileInputStream實現圖片的複製
		 */
		FileInputStream fis = new FileInputStream("d:/hmbb.ICO");
		FileOutputStream fos = new FileOutputStream("d:/hmbb2.ICO");
		byte[] bytes = new byte[1024*100];
		int len = 0;
		while((len = fis.read(bytes)) != -1){
			fos.write(bytes,0,len);
		}
		fis.close();
		fos.close();
		System.out.println("over");
		

	}

}

BufferedInputStream/BufferedOutputStream

Object ---> OutputStream ---> FileOutputStream ---> BufferedOutputStream

Object ---> IntputStream ---> FileInputStream ---> BufferedInputStream

package IO;

import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class BufferedInputStreamDemo {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("d:/aa.txt");
		BufferedInputStream bis = new BufferedInputStream(fis);
		int i = 0;
		while((i = bis.read()) != -1){
			char c = (char)i;
			System.out.print(c);
		}
		bis.close();			//先關閉外面
		fis.close();
		

	}

}

ByteArrayOutputStream(位元組陣列輸出流)/ByteArrayInputStream

ByteArrayOutputStream  此類實現了一個輸出流,其中的資料被寫入一個 byte 陣列。緩衝區會隨著資料的不斷寫入而自動增長。可使用 toByteArray()toString() 獲取資料。也就是在記憶體中開闢空間存取資料

package IO;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class ByteArrayOutputStreamDemo {

	public static void main(String[] args) throws Exception {
		/**
		 * 寫入
		 */
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(10);
		baos.write(127);
		baos.write(255);
		baos.write(256);		//256二進位制為 1 0000 0000 但範圍是0~255,所以只寫入低八位,因此讀出0
		byte[] bytes = baos.toByteArray();
		baos.close();
		
		/**
		 * 讀取
		 */
		ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
		int i = 0 ;
		while((i = bais.read()) != -1){
			System.out.println(i);
		}

	}

}

package IO;

public class IntAndByte {

	public static void main(String[] args) {
		int i =255 ;
		byte[] bytes = intByteArray(i);
		System.out.println(bytes);
		int i2 = byteArrayInt(bytes);
		System.out.println(i2);

	}
	/**
	 * 將int轉換成byte
	 */
	public static byte[] intByteArray(int i){
		byte[] bytes = new byte[4];
		//處理低位開始第一個byte
		bytes[0] = (byte)i;
		//處理低位開始第二個byte
		bytes[1] = (byte)(i >> 8);
		//處理低位開始第三個byte
		bytes[1] = (byte)(i >> 16);
	    //處理低位開始第四個byte
		bytes[1] = (byte)(i >> 24);
		return bytes;
	}
	
	/**
	 * 將byte轉換成int
	 */
	public static int byteArrayInt(byte[] arr){
		int i3 = arr[3] << 24;
		int i2 = (arr[2] & 0xFF) << 16;
		int i1 = (arr[1] & 0xFF) << 8;
		int i0 = arr[0] & 0xFF;
		return i3 | i2 | i1 | i0 ;
	}

}

InputStreamReader/OutputStreamWriter轉換流

InputStreamReader 是位元組流通向字元流的橋樑:它使用指定的 charset 讀取位元組並將其解碼為字元。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺預設的字符集。為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader

package IO;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

public class InputStreamReaderDemo {

	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("d:/aa.txt");
		InputStreamReader isr = new InputStreamReader(fis,"gbk");//指定字符集
		BufferedReader br = new BufferedReader(isr);			 //為了達到最高效率,在 BufferedReader 內包裝 InputStreamReader
		int len = 0;
		char[] buf = new char[1024];
		while((len = br.read(buf)) != -1){
			System.out.print(new String(buf,0,len));
		}
		br.close();
		isr.close();
		fis.close();

	}

}

OutputStreamWriter 是字元流通向位元組流的橋樑,可使用指定的 charset 將要寫入流中的字元編碼成位元組。它使用的字符集可以由名稱指定或顯式給定,否則將接受平臺預設的字符集。為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁呼叫轉換器。

package IO;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

public class OutputStreamWriterDemo {

	public static void main(String[] args) throws Exception {
		FileOutputStream fos = new FileOutputStream("d:/c.txt",true);	//true為追加而不是覆蓋
		OutputStreamWriter osw = new OutputStreamWriter(fos);
		BufferedWriter bw = new BufferedWriter(osw);	//為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁呼叫轉換器。
		bw.write("我懂了,I see");
		bw.close();
		osw.close();
		fos.close();
		
		//以上程式碼可簡寫為
		BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/c.txt",true)));
		bw2.write("合成程式碼");
		bw2.close();

	}

}

標準IO流

package IO;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class StandardIO {

	/*
	 * 標準IO
	 */
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String line = "";
		while((line = br.readLine()) != null){		//Buffered中有readLine()這個方法
			if(line.equals("exit")){
				System.exit(-1);
			}
			System.out.println(line);
		}
		br.close();

	}

}

File

File類:用來將檔案或者資料夾封裝成物件,分別對檔案與資料夾的屬性資訊進行操作,File物件可以作為引數傳遞給流的構造函                數。

目錄:檔案所在資料夾的路徑(不包括檔案)

路徑:精準定位檔案的地址

File基本操作及常用方法:

1.renameTo(File dest) 重新命名此抽象路徑名錶示的檔案(其實相當於移動檔案)。返回:當且僅當重新命名成功時,返回 true;    否則返回 false

File fi = new File("d:/a.txt");
fi.renameTo(new File("e:/b.txt"));		//結果是D盤的a.txt被移動到E盤並重命名為b.txt

2.getAbsolutePath() 返回此抽象路徑名的絕對路徑名字串

3.getName() 返回檔名

4.getParent() 返回此抽象路徑名父目錄的路徑名字串

package IO;

import java.io.File;
import java.io.FileOutputStream;

public class FileDemo {

	public static void main(String[] args) throws Exception {
		File f = new File("d:/aa.txt");
		System.out.println(f.exists());
		System.out.println(f.getAbsolutePath()); //返回絕對路徑
		System.out.println(f.getName());		 //返回檔名
		System.out.println(f.getParent());       //返回目錄
		
		f = new File("d:/f.txt");
		if(!f.exists()){
			//建立空檔案
			f.createNewFile();
		}
		
		if(f.exists()){
			//刪除檔案
			f.delete();
		}
		//目錄
		f = new File("d:/a/a1");
		//建立目錄
		f.mkdirs();
		//通過目錄和檔名構造File物件
		f = new File(f,"a.txt");
		f.createNewFile();
		
		FileOutputStream fos = new FileOutputStream(f);
		fos.write("abcdefg".getBytes());
		fos.close();
		
		//list返回一個字串陣列,這些字串指定此抽象路徑名錶示的目錄中的檔案和目錄
		f = new File("d:/Downloads");
		String[] names = f.list();
		for(String str : names){
			System.out.println(str);
		}

	}

}

RandomAccessFile (隨機訪問檔案)

構造方法:

建立從中讀取和向其中寫入(可選)的隨機訪問檔案流,該檔案                      由 File 引數指定。mode如下:

"rw" 開啟以便讀取和寫入。如果該檔案尚不存在,則嘗試建立該檔案。
"rws" 開啟以便讀取和寫入,對於 "rw",還要求對檔案的內容或元資料的每個更新都同步寫入到底層儲存裝置。
"rwd"   開啟以便讀取和寫入,對於 "rw",還要求對檔案內容的每個更新都同步寫入到底層儲存裝置。

2.建立從中讀取和向其中寫入(可選)的隨機訪問檔案流,該檔案具有指定名稱。

方法:

1.void seek(long pos) 設定到此檔案開頭測量到的檔案指標偏移量,在該位置發生下一個讀取或寫入操作。

 pos :從檔案開頭以位元組為單位測量的偏移量位置,在該位置設定檔案指標。

2. int 嘗試跳過輸入的 n 個位元組以丟棄跳過的位元組。返回實際跳過的位元組數。

3. void (long newLength) 設定此檔案的長度。(相當於給文件分配空間)。

4. long 返回此檔案中的當前偏移量。

package IO;

import java.io.RandomAccessFile;

public class RandomAccessFileDemo {

	public static void main(String[] args) throws Exception {
		RandomAccessFile raf = new RandomAccessFile("d:/aa.txt", "rw"); 
		raf.writeBytes("mememem");//預設從頭開始覆蓋
		raf.seek(raf.length()); //跳到文件尾,此時再寫入就成了追加。
		raf.writeBytes("bbbb");
		
		raf.close();

	}

}

檔案切割:

package IO;

import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;

public class FileSplitter {

	public static void main(String[] args) throws Exception {
		//原始檔
		File srcFile = new File("d:/aa.txt");
		//隨機訪問
		RandomAccessFile raf = new RandomAccessFile(srcFile, "r");
		//檔案總長度
		long totalLength = srcFile.length();
		//檔案份數
		int number = 3;
		//計算平均每個檔案長度,最後一份特殊
		int fileLength = (int)totalLength/number;
		//迴圈份數,讀寫檔案
		for(int i = 0 ; i < number ; i++){
			System.out.println("迴圈" + i);
			//開始指標
			int startIndex = i * fileLength ;
			//處理結束指標
			int endIndex = 0;
			if (i == (number-1)) {
				endIndex = (int)totalLength -1 ;
			} 
			else {
				endIndex = (i+1) * fileLength - 1;

			}
			FileOutputStream fos = new FileOutputStream(srcFile.getAbsolutePath() + "_" + i);
			raf.seek(startIndex);
			while(true){
				int itmp = raf.read();//一個位元組一個位元組讀
				fos.write(itmp);
				if(raf.getFilePointer() > endIndex){
					break;
				}
			}
			fos.close();
			System.out.println("結束");
		}

	}

}

加入緩衝區,加快速度

package IO;

import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;

public class FileSplitter {

	public static void main(String[] args) throws Exception {
		//原始檔
		File srcFile = new File("d:/iphone.exe");
		//隨機訪問
		RandomAccessFile raf = new RandomAccessFile(srcFile, "r");
		//檔案總長度
		long totalLength = srcFile.length();
		//檔案份數
		int number = 3;
		//計算平均每個檔案長度,最後一份特殊
		int fileLength = (int)totalLength/number;
		//迴圈份數,讀寫檔案
		for(int i = 0 ; i < number ; i++){
			System.out.println("迴圈" + i);
			//開始指標
			int startIndex = i * fileLength ;
			//處理結束指標
			int endIndex = 0;
			if (i == (number-1)) {
				endIndex = (int)totalLength -1 ;
			} 
			else {
				endIndex = (i+1) * fileLength - 1;

			}
			//建立檔案輸出流
			FileOutputStream fos = new FileOutputStream(srcFile.getAbsolutePath() + "_" + i);
			raf.seek(startIndex);
			//定義緩衝區
			byte[] buf = new byte[1024];
			while(true){
				//得到當前檔案指標
				int currPointer = (int)raf.getFilePointer();
				int remain = endIndex - currPointer + 1;
				if(remain >= buf.length){
					raf.read(buf);
					fos.write(buf);
				}
				else{
					raf.read(buf, 0, remain);
					fos.write(buf, 0, remain);
				}
				if(raf.getFilePointer() > endIndex){
					break;
				}
			}
			fos.close();
			System.out.println("結束");
		}

	}

}

ObjectInputStream/ObjtceOutputStream

對物件進行輸入和輸出,將java物件變成位元組陣列流byte[] 。

package IO;

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

public class ObjectStreamDemo {

	public static void main(String[] args) throws Exception {
		FileOutputStream fos = new FileOutputStream("d:/data.txt");
		//物件輸出流
		ObjectOutputStream oos = new ObjectOutputStream(fos);	//包裝
		oos.writeObject(new String("Hello world"));//寫入的是一個物件,但此時如果開啟data.txt會發現有亂碼
		oos.close();
		fos.close();
		System.out.println("over");
		
		//讀取檔案
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data.txt"));
		String str = (String) ois.readObject();
		System.out.println(str);
		ois.close();

	}

}

輸入時將物件轉化成了序列的二進位制流,因此開啟data.txt檔案出現亂碼,輸出時將二進位制流逆轉化為物件,所以輸出的和輸入的相同。

自己定義的JavaBean,要想實現 序列化需要實現Serializable介面,如下:

package IO;

import java.io.Serializable;

public class Cat implements Serializable{
	private String name ;
	private int age ;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Cat(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	

}
package IO;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class SerializableDemo {

	public static void main(String[] args) throws Exception {
		List<Cat> list = new ArrayList<Cat>();
		for(int i = 0 ; i < 100 ; i++){
			list.add(new Cat("tom" + i,i));
		}
		/*****************寫入(序列)********************/
		//位元組陣列輸出流
		ByteArrayOutputStream baos = new ByteArrayOutputStream();	//選它是因為要把流寫入記憶體中,FileOutputStream(“”)是把流寫入到指定檔案中
		//物件輸出流
		ObjectOutputStream oos = new ObjectOutputStream(baos);
		oos.writeObject(list);
		oos.close();
		baos.close();
		
		/*****************讀取(反序列)***********************/
		byte[] bytes = baos.toByteArray();
		ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(bais);
		list = (List<Cat>) ois.readObject();
		ois.close();
		bais.close();
		
		for(Cat c : list){
			System.out.println(c.getName() + "-" + c.getAge());
		}

	}

}

transient的作用及使用方法

我們都知道一個物件只要實現了Serilizable介面,這個物件就可以被序列化,java的這種序列化模式為開發者提供了很多便利,我們可以不必關係具體序列化的過程,只要這個類實現了Serilizable介面,這個類的所有屬性和方法都會自動序列化。然而在實際開發過程中,我們常常會遇到這樣的問題,這個類的有些屬性需要序列化,而其他屬性不需要被序列化,打個比方,如果一個使用者有一些敏感資訊(如密碼,銀行卡號等),為了安全起見,不希望在網路操作(主要涉及到序列化操作,本地序列化快取也適用)中被傳輸,這些資訊對應的變數就可以加上transient關鍵字。換句話說,這個欄位的生命週期僅存於呼叫者的記憶體中而不會寫到磁盤裡持久化。總之,java 的transient關鍵字為我們提供了便利,你只需要實現Serilizable介面,將不需要序列化的屬性前新增關鍵字transient,序列化物件的時候,這個屬性就不會序列化到指定的目的地中。

DataInputStream/DataOutputStream(資料輸入/輸出流)

資料輸入流允許應用程式以與機器無關方式從底層輸入流中讀取基本 Java 資料型別。應用程式可以使用資料輸出流寫入稍後由資料輸入流讀取的資料。