11.IO流

可乐爱兑姜汁發表於2024-04-14

第十一章【IO流】

一、流的概念

​ 資料以二進位制的形式在程式裝置之間流動傳輸,就像水在管道里流動一樣,所以就把這種資料傳輸的方式稱之為輸入流、輸出流。

二、流的分類

根據資料的流向分為:輸入流和輸出流

  • 輸入流 :把資料從其他裝置上讀取到程式中的流

  • 輸出流 :把資料從程式中寫出到其他裝置上的流

根據資料的型別分為:位元組流和字元流

  • 位元組流 :以位元組為單位(byte),讀寫資料的流

  • 字元流 :以字元為單位(char),讀寫資料的流

總的分類:

  • 位元組輸入流,在程式中,以位元組的方式,將裝置(檔案、記憶體、網路等)中的資料讀進來

  • 位元組輸出流,在程式中,以位元組的方式,將資料寫入到裝置(檔案、記憶體、網路等)中

  • 字元輸入流,在程式中,以字元的方式,將裝置(檔案、記憶體、網路等)中的資料讀進來

  • 字元輸出流,在程式中,以字元的方式,將資料寫入到裝置(檔案、記憶體、網路等)中

三、流的結構

幾乎所有的流,都是派生自四個抽象的父型別:

  • InputStream,代表位元組輸入流型別

  • OutputStream,代表位元組輸出流型別

  • Reader,代表字元輸入流型別

  • Writer,代表字元輸出流型別

基本流【節點流】:

​ 位元組輸入輸出流:xxxInputStream/xxxOutputStream 【xxx:裝置】

​ 字元輸入輸出流:xxxReader/xxxWriter

包裝流:位元組輸入輸出流,字元輸入輸出流

image-20210308195603878

一般情況下,一個流,會具備最起碼的三個特點:

  • 是輸入還是輸出
  • 是位元組還是字元
  • 流的目的地

四、位元組流

1、概述

java.io.InputStream是所有位元組輸入流的抽象父型別

java.io.OutputStream是所有位元組輸出流的抽象父型別

在程式碼中,使用流運算元據的的基本步驟是:

  1. 宣告流
  2. 建立流
  3. 使用流
  4. 關閉流
2、控制檯

讓程式一直讀取和寫出,那麼可以加入while迴圈,遇到“bye”結束

public class InputAndOutputStreamTest3 {
	public static void main(String[] args) {
		//1.宣告流
		InputStream in = null;
		OutputStream out  = null;
		//2.建立流
		in = System.in;
		out  = System.out;
		//3.使用流
		int num = -1;
		byte[] by = new byte[1024];
		try {
			while ((num = in.read(by)) != -1) {
				out.write(by, 0, num);
				out.flush();
				if(by[num -1] == 10 && by[num -2] == 13) {
					num = num - 2;
				}
				String str = new String(by, 0, num);
				if(str.equals("bye")) {
					break;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//4.關閉流
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
3、位元組陣列

java.io.ByteArrayInputStream負責從位元組陣列中讀取資料

java.io.ByteArrayOutputStream負責把資料寫入到位元組陣列中

使用位元組流,從位元組陣列中讀取資料,以及向位元組陣列中寫資料。

public class ByteArrayStreamTest {
	public static void main(String[] args) {
		//1.宣告流
		InputStream in = null;
		OutputStream out = null;
		//2.建立流
		byte[] arr = "hello world".getBytes();
		in = new ByteArrayInputStream(arr);
		out = new ByteArrayOutputStream();
		//3.使用流
		int len = -1;
		byte[] by = new byte[1024];
		try {
			len = in.read(by);
			out.write(by, 0, len);
			out.flush();
			//4.視覺化到控制檯
			String str = out.toString();
			System.out.println(str);
			//5.呼叫ByteArrayOutputStream中的toByteArray方法,可以將寫入到out物件中的資料返回
			byte[] array = ((ByteArrayOutputStream)out).toByteArray();
			System.out.println(Arrays.toString(array));
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			//6.關閉流
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
4、管道

java.io.PipedInputStream負責從管道中讀取資料

java.io.PipedOutputStream負責將資料寫入到管道中

使用位元組流,可以從管道中讀取資料,以及向管道中寫資料。

public class PipedStreamTest {
	public static void main(String[] args) {
		//1.宣告流
		PipedInputStream in = null;
		PipedOutputStream out = null;
		//2.建立流
		in = new PipedInputStream();
		out = new PipedOutputStream();
		//3.管道對接
		try {
			in.connect(out);
			
			Thread t1 = new WriterThread(out);
			Thread t2 = new ReaderThread(in);
			t1.start();
			t2.start();
			t1.join();
			t2.join();
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		System.out.println();
		System.out.println("程式執行結束");
	}
}

class WriterThread extends Thread{
	private OutputStream out;
	public WriterThread(OutputStream out) {
		this.out = out;
	}
	@Override
	public void run() {
		byte[] arr = "hello world".getBytes();
		
		try {
			for (int i = 0; i < arr.length; i++) {
				out.write(arr[i]);
				out.flush();
				Thread.sleep(100);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

class ReaderThread extends Thread{
	private InputStream in;
	public ReaderThread(InputStream in) {
		this.in = in;
	}
	@Override
	public void run() {
		int len = -1;
		try {
			while ((len = in.read()) != -1) {
				System.out.write(len);
				System.out.flush();
			}
			System.out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
5、檔案

java.io.File類,是java中對檔案和目錄的抽象表示,主要用於檔案和目錄的建立、查詢和刪除等操作。

常用方法:

public String getAbsolutePath(),返回file的絕對路徑

public String getPath() ,返回建立file物件時傳入的路徑引數(有可能是相對路徑)

public String getName(),返回file的名字

public long length(),file如果表示檔案,則返回檔案內容的長度(位元組個數)

public boolean exists(),判斷此檔案或目錄是否真的存在

public boolean isDirectory() ,判斷File表示的是否是一個目錄

public boolean isFile(),判斷file表示的是否是一個檔案

使用位元組流,可以從檔案中讀取資料,以及向檔案中寫資料。

java.io.FileInputStream,負責從檔案中讀取資料

java.io.FileOutputStream,負責把資料寫入到檔案中

public class FileStreamTest {
	public static void main(String[] args) {
		//1.宣告流
		InputStream in = null;
		OutputStream out = null;
		
		//2.建立流
		try {
			File f1 = new File("src/com/sxu/day19/test/a.txt");
			File f2 = new File("src/com/sxu/day19/test/b.txt");
			in = new FileInputStream(f1);
			out = new FileOutputStream(f2);
			
			//3.使用流
			int len = -1;
			byte[] by = new byte[1024];
			
			while ((len = in.read(by)) != -1) {
				out.write(by,0,len);
			}
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
6、網路

轉至 12.網路程式設計.md

五、字元流

1、概述

字元流,可以用字元的形式,讀寫資料,專門用於處理文字資料。

java.io.Reader是所有字元輸入流的抽象父型別

java.io.Writer是所有字元輸出流的抽象父型別

2、字元陣列

使用字元流,從字元陣列中讀取資料,以及向字元陣列中寫資料。

java.io.CharArrayReader負責從字元陣列中讀取資料

java.io.CharArrayWriter負責把資料寫入到字元陣列中

public class ReaderAndWriterStreamTest {
	public static void main(String[] args) {
		//1.宣告流
		Reader in = null;
		Writer out = null;
		
		//2.建立流
		char[] arr = "hello world".toCharArray();
		in = new CharArrayReader(arr);
		out = new CharArrayWriter();
		
		//3.使用流
		int len = -1;
		char[] ch = new char[1024];
		try {
			len = in.read(ch);
			out.write(ch, 0, len);
			out.flush();
			
			String str = out.toString();
			System.out.println(str);
			
			//CharArrayWriter中的toCharArray方法,可以將寫入到out物件中的資料返回
			char[] charArray = ((CharArrayWriter)out).toCharArray();
			System.out.println(Arrays.toString(charArray));
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
3、管道

使用字元流,可以從管道中讀取資料,以及向管道中寫資料。

java.io.PipedReader負責從管道中讀取資料

java.io.PipedWriter負責將資料寫入到管道中

public class PipedTest {
	public static void main(String[] args) {
		PipedReader in = null;
		PipedWriter out = null;
		
		in = new PipedReader();
		out = new PipedWriter();
		
		try {
			in.connect(out);
			
			Thread t1 = new WriterThreaed(out);
			Thread t2 = new ReaderThread(in);
			
			t1.start();
			t2.start();
			t1.join();
			t2.join();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println();
		System.out.println("程式執行結束");
	}
}

class WriterThreaed extends Thread{
	private Writer out;
	public WriterThreaed(Writer out) {
		this.out = out;
	}
	@Override
	public void run() {
		char[] arr = "hello world".toCharArray();
		
		try {
			for (int i = 0; i < arr.length; i++) {
				out.write(arr[i]);
				out.flush();
				Thread.sleep(100);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

class ReaderThread extends Thread{
	private Reader in;
	public ReaderThread(Reader in) {
		this.in = in;
	}
	@Override
	public void run() {
		int len = -1;
		
		try {
			while ((len = in.read()) != -1) {
				System.out.write(len);
				System.out.flush();
			}
			System.out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
4、檔案

使用字元流,可以從檔案中讀取資料,以及向檔案中寫資料。

java.io.FileReader ,負責從檔案中讀取資料

java.io.FileWriter ,負責把資料寫入到檔案中

public class FileTest {
	public static void main(String[] args) {
		//1.宣告流
		Reader in = null;
		Writer out = null;
		
		try {
			//2.建立流
			File f1 = new File("src/com/sxu/day20/test/a.txt");
			File f2 = new File("src/com/sxu/day20/test/b.txt");
			
			in = new FileReader(f1);
			out = new FileWriter(f2);
			
			//3.使用流
			int len = -1;
			char[] ch = new char[1024];
			
			while ((len = in.read(ch)) != -1) {
				out.write(ch,0,len);
			}
			out.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(out != null) {
				try {
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
5、其他

其他情況,使用字元流進行讀寫資料時,可以藉助於位元組流,將位元組流轉換為字元流來操作。因為字元流底層也是以位元組為單位來運算元據的,只不過中間會把位元組按照預設或指定的字元編號,把位元組轉成了字元而已。

六、節點流

位元組流和字元流,都屬於節點流

它們的特點是,可以【直接】讀取某一個地方的資料,或者【直接】把資料寫入到某一個地方。

七、資料流

DataOutputStream負責把指定型別的資料,轉化為位元組並寫出去

DataInputStream負責把讀取到的若干個位元組,轉化為指定型別的資料

八、緩衝流

位元組緩衝流

java.io.BufferedInputStream,負責給位元組輸入流提供緩衝功能

java.io.BufferedOutputStream,負責給位元組輸出流提供緩衝功能

字元緩衝流

java.io.BufferedReader,負責給字元輸入流提供緩衝功能

java.io.BufferedWriter,負責給字元輸出流提供緩衝功能

九、轉換流

java.io.OutputStreamWriter ,可以將位元組輸出流轉換為字元輸出流,並指定編碼

java.io.InputStreamReader,可以將位元組輸入流轉換為字元輸入流,並指定編碼

十、物件流

在java中,並非所有物件都可以進行序列化和反序列化,而是隻有實現了指定介面的物件才可以進行。java.io.Serializable介面
java.io.ObjectOutputStream,將Java物件轉換為位元組序列,並輸出到記憶體、檔案、網路等地方java.io.ObjectInputStream,從某一個地方讀取出物件的位元組序列,並生成對應的物件

java中的關鍵字transient,可以修飾類中的屬性,它的讓物件在進行序列化的時候,忽略掉這個被修飾的屬性

十一、隨機訪問流

java.io.RandomAccessFile是JavaAPI中提供的對檔案進行隨機訪問的流

相關文章