菜鳥學習筆記:Java提升篇6(IO流2——資料型別處理流、列印流、隨機流)

呼呼哈哈嘿嘿發表於2020-12-20


上一節講解的是我們工作中常用的流,需要大家重點掌握,除此之外Java中還有一些流需要大家瞭解。

位元組陣列輸入輸出流

ByteArrayInputStream和ByteArrayOutputStream是位元組陣列的輸入輸出流,操作與正常輸入輸出流一致,只是接收的是一個位元組陣列,我們直接看程式碼:

	public static void main(String[] args) throws IOException {
		read(write());		
	}
	public static byte[] write() throws IOException{
		//目的地
		byte[] dest;
		//選擇流不同點:輸出流操作與檔案輸出流有些不同,有新增方法,不能使用多型
		ByteArrayOutputStream bos =new ByteArrayOutputStream();
		//操作 寫出
		String msg ="操作與 檔案輸入流操作一致";
		byte[] info =msg.getBytes();
		bos.write(info, 0, info.length);
		//獲取資料
		dest =bos.toByteArray();
		//釋放資源
		bos.close();
		return dest;
	}
	public static void read(byte[] src) throws IOException{
		//資料來源傳入	
		
		//選擇流,傳入的不再是檔案物件,而是一個字元陣列
		InputStream is =new BufferedInputStream(
					new ByteArrayInputStream(
							src
						)
				);
		//操作
		byte[] flush =new byte[1024];
		int len =0;
		while(-1!=(len=is.read(flush))){
			System.out.println(new String(flush,0,len));
		}
		//釋放資源(可以不用)
		is.close();	
	}

資料型別處理流

基本資料型別

DataInputStream和DataOutputStream為資料處理流,他們可以將固定型別的資料讀出到檔案中,也可以從檔案中讀取有相應型別的資料,同樣直接看程式碼:

	public static void write(String destPath) throws IOException{
		double point =2.5;
		long num=100L;
		String str ="資料型別";
		
		//建立源
		File dest =new File(destPath);
		//選擇流  DataOutputStream
		DataOutputStream dos =new DataOutputStream(
					new BufferedOutputStream(
								new FileOutputStream(dest)
							)
				);
		//操作 寫出的順序 為讀取準備
		dos.writeDouble(point);
		dos.writeLong(num);
		dos.writeUTF(str);		
		dos.flush();
		
		//釋放資源
		dos.close();
	}

輸出檔案結果:
輸出檔案
可以看到輸出的檔案是十六進位制數,這個表示的是我們所選型別的資料,可以通過DataInputStream讀取。

	public static void read(String destPath) throws IOException{
		//建立源
		File src =new File(destPath);
		//選擇流
		DataInputStream dis =new DataInputStream(
					new BufferedInputStream(
								new FileInputStream(src)
							)
				);
		
		//操作 讀取的順序與寫出一致   必須存在才能讀取
		//不一致,資料存在問題
		long num2 =dis.readLong();
		double num1 =dis.readDouble();
		String str =dis.readUTF();
		
		dis.close();
		System.out.println(num2+"-->"+str);
		
	}

程式結果:讀入結果

引用型別

將引用型別資料(也就是物件)儲存到檔案中的過程叫做序列化,而將儲存到檔案中物件讀取到程式中的過程稱為反序列化。序列化和反序列化也是建立物件的一種方式(面試考點)。
對於序列化和反序列化有幾點需要注意:

  • 必須先序列化後反序列化,反序列化順序必須與序列化一致。
  • 只有實現了java.io.Serializable介面才能被序列化。序列化的類中使用triansient修飾的屬性可以避免被序列化。

針對序列化和反序列化的問題Java提供了ObjectInputStream和ObjectOutputStream流來進行讀寫,接下來用程式碼來說明其過程:
我們先定義一個實現java.io.Serializable介面的類,在不需要序列化的屬性前可以加上transient:

public class Employee implements java.io.Serializable {
	//不需要序列化的屬性
	private transient String name;
	private double salary;
	public Employee() {
	}
	public Employee(String name, double salary) {
		super();
		this.name = name;
		this.salary = salary;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
}

然後對這個類進行序列化操作,操作過程與之前類似:

	public static void seri(String destPath) throws IOException{
		Employee emp =new Employee("張三",1000000);
		int[] arr ={1,2,3,45};
		//建立源
		File dest =new File(destPath);
		//選擇流  ObjectOutputStream
		ObjectOutputStream dos =new ObjectOutputStream(
					new BufferedOutputStream(
								new FileOutputStream(dest)
							)
				);
		//操作 寫出的順序 為讀取準備
		dos.writeObject(emp);
		dos.writeObject(arr);
		//釋放資源
		dos.close();
	}

序列化結果:
序列化
同樣我們可以把檔案反序列化讀入程式:

	public static void read(String destPath) throws IOException, ClassNotFoundException{
		//建立源
		File src =new File(destPath);
		//選擇流
		ObjectInputStream dis =new ObjectInputStream(
					new BufferedInputStream(
								new FileInputStream(src)
							)
				);
		
		//操作 讀取的順序與寫出一致   必須存在才能讀取
		//不一致,資料存在問題
		Object obj =dis.readObject();
		if(obj instanceof Employee){
			Employee emp=(Employee)obj;
			System.out.println(emp.getName());
			System.out.println(emp.getSalary());
		}
		
		obj =dis.readObject();
		int[] arr=(int[])obj;
		System.out.println(Arrays.toString(arr));
		dis.close();
	}

結果如下:
反序列化

列印流

PrintStream和InputStream是Java中的列印流,看著比較陌生,但我們基本每次寫程式都在用,println這個方法大家再熟悉不過了吧,它就是PrintStream物件的方法,換句話說,System.out返回的就是PrintStream類。
列印流除了可以和控制檯直接互動之外,也可以進行檔案寫出地操作,如下例所示,但用的不多做了解即可。

	public static void main(String[] args) throws FileNotFoundException {
		System.out.println("test");
		//接收PrintStream物件
		PrintStream ps =System.out;
		ps.println(false);
		
		
		//輸出到檔案
		File src = new File("e:/xp/test/print.txt");
		ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(src)));
		ps.println("io is so easy....");
		
		ps.close();
	}

System.in、System.out、System.err

System.outSystem.err返回的PrintStream都是向控制檯輸出的流,他們的原理沒有什麼本質區別,你可以理解為System.err就是System.out輸出時把字型改為紅色。
System.in是標準輸入流,一般配合Senner流一起使用,可以接受我們鍵盤的輸入。同樣的我們也可以用其來讀取檔案內容:

	public static void main(String[] args) throws FileNotFoundException {
		InputStream is =System.in;  //鍵盤輸入
		//is = new BufferedInputStream(new FileInputStream("e:/xp/test/print.txt"));
		Scanner sc = new Scanner(is);
		System.out.println(sc.nextLine());//也是一行一行讀
	}

在System類中我們也可以通過setOut指定輸出位置:

	public static void main(String[] args) throws FileNotFoundException {
		//重定向
		System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("e:/xp/test/print.txt")),true));
		//第二個引數true表示自動重新整理,也就是自動呼叫flush方法
		System.out.println("a");  //控制檯  -->檔案		
		System.out.println("test");
		//回控制檯	
		System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));
		//FileDescriptor類代表控制檯,常用的有FileDescriptor.in、FileDescriptor.out、FileDescriptor.err
		System.out.println("back....");
	}

同樣我們也可以用BufferedReader對列印流進行包裹,從而可以通過readLine()方法進行鍵盤讀入:

	public static void main(String[] args) throws IOException {
		InputStream is =System.in;
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		System.out.println("請輸入。。。。");
		String msg =br.readLine();
		System.out.println(msg);
	}

隨機流RandomAccessFile

這個流不屬於IO流,但支援對檔案的讀取和寫入隨機訪問。它的原理是首先把隨機訪問的檔案物件看作儲存在檔案系統中的一個大型 byte 陣列,然後通過指向該 byte 陣列的游標或索引(即:檔案指標 FilePointer)在該陣列任意位置讀取或寫入任意資料。
RandomAccessFile最重要的是它的seek方法,它可以指定檔案讀取的初始位置,案例如下:

	public static void main(String[] args) throws IOException {
		RandomAccessFile rnd =new RandomAccessFile(new File("E:/xp/20130502/test/test.java"),"r");
		//第二個引數"r"表示只讀
		//從檔案第40個位元組開始讀
		rnd.seek(40);
		//定義緩衝大小
		byte[] flush =new byte[1024];
		//接收長度
		int len =0; 
		//列印讀取的前20個位元組所代表的內容		
		while(-1!=(len=rnd.read(flush))){
			if(len>=20){
				System.out.println(new String(flush,0,20));
				break;
			}else{
				System.out.println(new String(flush,0,len));
			}
		}
		rnd.close();
	}

運用這個流操作我們可以完成檔案的分割,大家有興趣可以自己試著實現。以上就是IO流的全部內容,這一章節需要理解的概念不多,主要以各種流的使用方法為主,所以例項很多,程式碼量也比較大,這就需要大家多讀多寫多練。做到可以熟練運用。
上一篇:菜鳥學習筆記:Java提升篇5(IO流1——IO流的概念、位元組流、字元流、緩衝流、轉換流)

相關文章