1. 程式人生 > >Java基礎---I/O流--序列流+PrintStream+轉換流+Serializable+Properties

Java基礎---I/O流--序列流+PrintStream+轉換流+Serializable+Properties

一、序列流
    SequenceInputStream (序列流) : 可以把多個輸入流串聯起來讀取,先從第一個開始i讀取,然後再下一個....
方式一:只合並兩個流
public SequenceInputStream(InputStream s1,InputStream s2)
    將按順序讀取這兩個引數,先讀取 s1 然後讀取 s2
    引數:兩個輸入流

	// 方式一:合併兩個檔案
	public static void merge1() throws IOException {
		// 找到目標檔案物件
		File inFile1 = new File("g:\\a.txt");
		File inFile2 = new File("g:\\b.txt");
		File outFile = new File("g:\\s.txt");
		// 第二步:建立資料的輸入輸出通道
		FileOutputStream fileOutputStream = new FileOutputStream(outFile);
		// 建立資料的輸入輸出通道
		FileInputStream fileInputStream1 = new FileInputStream(inFile1);
		fileInputStream2 = new FileInputStream(inFile2);
		// 建立序列流物件
		SequenceInputStream sequenceInputStream = new SequenceInputStream(fileInputStream1, fileInputStream2);
		// 邊讀邊寫
		byte[] buf = new byte[1024];
		int length = 0;
		while ((length = sequenceInputStream.read(buf)) != -1) {
			fileOutputStream.write(buf, 0, length);
		}
		// 關閉資源
		sequenceInputStream.close();
		fileOutputStream.close();
	}

方式二:合併多個流   (重點是構造迭代器)
public SequenceInputStream(Enumeration<? extends InputStream> e)
    將按順序讀取由該列舉生成的輸入流,呼叫該流的 close 方法將其關閉
    引數:必須是InputStream物件的Enumeration型引數

	// 把三個檔案合併成一個。
	public static void merge2() throws IOException {
		// 找到目標檔案物件
		File inFile1 = new File("g:\\a.txt");
		File inFile2 = new File("g:\\b.txt");
		File inFile3 = new File("g:\\c.txt");
		File outFile = new File("g:\\s.txt");

		// 建立資料的輸入輸出通道
		FileOutputStream fileOutputStream = new FileOutputStream(outFile);
		FileInputStream fileInputStream1 = new FileInputStream(inFile1);
		FileInputStream fileInputStream2 = new FileInputStream(inFile2);
		FileInputStream fileInputStream3 = new FileInputStream(inFile3);

		// 通過Vector得到一個迭代器。
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(fileInputStream1);
		v.add(fileInputStream2);
		v.add(fileInputStream3);
		Enumeration<FileInputStream> e = v.elements();
		// 建立一個序列流物件
		SequenceInputStream inputStream = new SequenceInputStream(e);
		// 建立緩衝陣列,邊讀邊寫
		byte[] buf = new byte[1024];
		int length = 0;
		while ((length = inputStream.read(buf)) != -1) {
			fileOutputStream.write(buf, 0, length);
		}
		// 關閉資源
		inputStream.close();
		fileOutputStream.close();

	}

應用:MP3檔案的切割與合併

//檔案切割與合併
public class SequenceInputStream2 {

	public static void main(String[] args) throws IOException {
		//cutFile();
		mergeFile();

	}

	// 切割mp3檔案
	public static void cutFile() throws IOException {
		File file = new File("g:/1.mp3");
		FileInputStream fileInputStream = new FileInputStream(file);
		byte[] buf = new byte[1024 * 1024];
		int length = 0;
		int count = 1;
		while ((length = fileInputStream.read(buf)) != -1) {
			// 每讀取一次,則生成一個檔案  注意檔案路徑的設定
			FileOutputStream fileOutputStream = new FileOutputStream("g:/music/" + count + ".mp3");
			// 把讀取到的資料寫出
			fileOutputStream.write(buf, 0, length);
			count++;
			// 關閉資源
			fileOutputStream.close();
		}
		// 關閉資源
		fileInputStream.close();
	}

	// 合併mp3檔案
	public static void mergeFile() throws IOException {
		// 資料夾路徑
		File dir = new File("g:/music");
		// 獲取到資料夾中的所有子檔案
		File[] files = dir.listFiles();
		// 建立一個Vector物件儲存FileInputStream物件
		Vector<FileInputStream> vector = new Vector<FileInputStream>();
		// 遍歷陣列,新增到集合
		for (int i = 0; i < files.length; i++) {
			if (files[i].getName().endsWith(".mp3")) {
				vector.add(new FileInputStream(files[i]));
			}
		}

		// 建立一個序列流物件
		SequenceInputStream inputStream = new SequenceInputStream(vector.elements());
		// 建立一個輸出流物件
		FileOutputStream fileOutputStream = new FileOutputStream("g:/合併.mp3");
		// 邊讀邊寫
		byte[] buf = new byte[1024];
		int length = 0;
		while ((length = inputStream.read(buf)) != -1) {
			fileOutputStream.write(buf, 0, length);
		}
		// 關閉資源
		fileOutputStream.close();
		inputStream.close();
	}

二、物件輸入輸出流
    ObjectOutputStream(物件的輸出流類): 把  物件資料  寫出到硬碟檔案上    序列化
    ObjectInputStream(物件的輸入流類): 把 硬碟中的  物件資料  讀取回來      反序列化 

        Serializable介面  沒有任何方法,這種介面稱作為標識介面
        serialVersionUID版本號 :通過類名、包名、工程名、成員一起計算得出的id號

序列反序列注意:
     1.ObjectOutputStream的writeObject方法只能寫出實現了Serializable介面的物件
     2.物件反序列化建立物件時是不會呼叫構造方法。
     3.把物件寫到檔案上時,檔案記錄物件資訊,還記錄class的版本號(serialVersionUID)
     4.反序列化時,jvm使用本地class檔案算出一個id號與檔案記錄的id號進行對比,如果不一致,反序列化失敗。
     5.如果一個類的成員可能在後期會發生改動,那麼可以在序列化之前就指定一個serialVersionUID , 如果一個類一家指定了一個serialVersionUID那麼java虛擬機器則不會再計算該class檔案的serialVersionUID了。 
     6.果一個類的某些成員不想被序列化到硬碟上,可以使用關鍵字transient修飾。 
     7.一個類的內部維 護了另外一個類物件,則另外一個類也必須要實現Serializable介面

//使用者類
class User implements Serializable {
	// 提前生成一個serialVersionUID
	private static final long serialVersionUID = -4964722333163184880L;
	String name;
	String password;
	transient int age; // transient 透明

	public User(String name, String password, int age) {

		this.name = name;
		this.password = password;
		this.age = age;

	}

	@Override
	public String toString() {
		return "User [name=" + name + ", password=" + password + ", age=" + age + "]";
	}

}

public class Serializable1 {
	private static ObjectInputStream inputStream;

	public static void main(String[] args) throws Exception {
		writeObj();
		readObj();
	}

	// 把物件寫到檔案上------>物件的序列化。
	public static void writeObj() throws IOException {
		User user = new User("chao", "ttt", 16);
		// 找到目標
		File file = new File("g:/obj.txt");
		// 建立資料的輸出通道
		FileOutputStream fileOutputStream = new FileOutputStream(file);
		// 建立物件的輸出流物件
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
		// 把物件寫出到輸出流中
		objectOutputStream.writeObject(user);
		// 關閉資源
		objectOutputStream.close();

	}

	// 物件的反序列化-----> 讀取硬碟中的物件到記憶體中。
	public static void readObj() throws Exception {
		// 找到目標檔案
		File file = new File("g:/obj.txt");
		// 建立資料的輸入流物件
		FileInputStream fileInputStream = new FileInputStream(file);
		inputStream = new ObjectInputStream(fileInputStream);
		// 讀取物件的資料
		// 反序列化的時候需要建立物件,建立物件需要依賴:Class檔案
		User user = (User) inputStream.readObject();
		// 測試檢視
		System.out.println("物件的資訊:" + user);

	}
}

Properties配置檔案類  (屬於Map集合體系)
    作用: 
        1. 生成配置檔案
        2. 讀取配置
    注意:
        1.新增資料時不要新增非字串型別的資料,否則強轉報錯
        2.新增中文字元資料,使用store方法時,使用字元流
        3.修改了properties裡面的資料,一定要重新生成一個配置檔案
        4.properties.setProperty(String key,String value)設定值或修改值(map)
        5.保證鍵值對為字串型別的資料
        6.properties.store(OutputStream out,String comments);  comments:描述隨便寫
                   store()方法寫入硬碟
        7.載入:載入配置檔案到Properties使用load方法 

  Properties建立+修改+讀取配置檔案

public class Properties1 {

	public static void main(String[] args) throws IOException {
		createProperties();
		readProperties();

	}

	// 建立一個配置檔案
	public static void createProperties() throws IOException {
		// 建立一個Properties物件
		Properties properties = new Properties();
		properties.setProperty("迪迦", "1234");
		properties.setProperty("奧特曼", "2345");
		properties.setProperty("abc", "4567");
		// 當存非中文資料時用位元組流
		// FileOutputStream fileOutputStream = new
		// FileOutputStream("g:/users.properties");
		FileWriter fileWriter = new FileWriter("g:/users.properties");
		// 利用Properties生成一個配置檔案。
		properties.store(fileWriter, "jinchao94"); // 第二個引數是使用一段文字對引數列表進行描述。
	}

	// 讀取配置檔案 ---- 載入配置檔案到Properties是使用load方法。
	public static void readProperties() throws IOException {
		// 建立一個Properties
		Properties properties = new Properties();
		// 建立輸入字元流物件
		FileReader fileReader = new FileReader("g:/users.properties");
		// 載入配置檔案的資料到Properties是使用load方法。
		properties.load(fileReader);
		// 遍歷元素
		Set<Entry<Object, Object>> set = properties.entrySet();
		for (Entry<Object, Object> entry : set) {
			System.out.println("鍵:" + entry.getKey() + "   值:" + entry.getValue());
		}

		// 修改奧特曼...
		properties.setProperty("奧特曼", "110");
		// 重新生成一個配置檔案
		properties.store(new FileWriter("g:/users.properties"), "jinchao94");
	}
}

 Properties應用:正版軟體:只能試用三次,三次之後提示購買正版並退出

public class Properties2 {
	public static void main(String[] args) throws IOException {
		// 先檢查是否存在配置檔案
		File file = new File("g:/usetime.properties");
		if (!file.exists()) {
			// ,如果不存在,建立配置檔案
			file.createNewFile();
		}
		// 建立一個Properties物件
		Properties properties = new Properties();
		// 載入配置檔案
		properties.load(new FileReader(file));
		// 定義一個變數記錄執行的次數
		int count = 0;
		// 如果配置檔案記錄了執行次數,則應該使用配置檔案的執行次數
		String num = properties.getProperty("num");
		if (num != null) {
			count = Integer.parseInt(num);
		}
		// 判斷是否已經運行了三次
		if (count == 3) {
			System.out.println("達到限制次數,請購買正版!!");
			System.exit(0);
		}
		count++;
		properties.setProperty("num", count + "");
		// count+""將count轉換成字串格式(自動)
		System.out.println("軟體已使用" + count + "次,還剩餘" + (3 - count) + "次");
		// 重新生成配置檔案
		properties.store(new FileWriter(file), "runtime");
	}
}

 PrintStream     列印(輸出)流: 
 列印流的好處:
     1. 列印流可以列印任意型別的資料。
     2. 列印流列印任意型別資料之前,會先把資料轉成字串然後再列印輸出
     3. 原樣輸出

	// 作用一:列印任意型別的資料
	public static void function1() throws FileNotFoundException {
		// 找到目標檔案
		File file = new File("g:/c.txt");
		// 建立列印流物件
		PrintStream printStream = new PrintStream(file);
		// 列印資料
		printStream.println(99160);
		// 關閉資源
		printStream.close();
	}

	// 作用二: 收集日誌資訊
	public static void function2() throws FileNotFoundException {
		File file = new File("g:/c.txt");
		FileOutputStream fileOutputStream = new FileOutputStream(file, true);
		PrintStream printStream = new PrintStream(fileOutputStream);

		try {
			str = null;
			System.out.println("字元個數:" + str.length());
			result = 4 / 0;
		} catch (Exception e) {

			e.printStackTrace(printStream);
		}

	}

轉換流:
InputStreamReader  :輸入位元組流轉換成輸入字元流
OutputStreamWriter :輸出位元組流轉換成輸出字元流     
轉換流的作用:
    1. 可以把位元組流轉換成字元流。
    2. 可以指定任意的碼錶進行讀寫資料。支援編碼指定

作用詳細說明:無非就是指定碼錶  所有轉換成字串輸出  快捷方便,功能強大

//轉換流
public class IOswitch {

	public static void main(String[] args) throws IOException {
		readTest1();
		writeTest1();
		readData();
		readData();

	}

	// 作用一、把輸入位元組流轉換成輸入字元流 -----> InputStreamReader
	// 此方法可從控制檯取一行資料,取代scanner方法
	public static void readTest1() throws IOException {
		// 先獲取標準 的輸入流
		InputStream in = System.in;
		// 把位元組流轉換成字元流
		InputStreamReader inputStreamReader = new InputStreamReader(in);
		// 一次讀取一行的功能 只有BufferedReader才有,故需要引用
		BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
		// 簡寫:一行頂三行
		// BufferedReader bufferedReader2 = new BufferedReader(new
		// InputStreamReader(System.in));
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			System.out.println(line);
		}

	}

	// 作用二、把輸出位元組流轉換成輸出字元流
	public static void writeTest1() throws IOException {
		FileOutputStream fileOutputStream = new FileOutputStream("g:/b.txt");
		String data = "hello world";
		OutputStreamWriter writer = new OutputStreamWriter(fileOutputStream);
		// 寫出資料
		writer.write(data);
		// 關閉資源
		writer.close();
	}

	// 作用三、指定碼錶讀取資料
	public static void readData() throws IOException {
		FileInputStream fileInputStream = new FileInputStream("g:/b.txt");
		// FileReader 預設使用的碼錶是gbk碼錶,而且不能指定碼錶讀。
		// 指定解碼格式
		InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
		char[] buf = new char[1024];
		int length = 0;
		while ((length = inputStreamReader.read(buf)) != -1) {
			System.out.println(new String(buf, 0, length));
		}
		// 關閉資源
		inputStreamReader.close();
	}

	// 指定碼錶進行寫資料
	public static void writeData() throws IOException {
		FileOutputStream fileOutputStream = new FileOutputStream("g:/b.txt");
		// FileWriter 預設使用的碼錶是gbk碼錶,而且不能指定碼錶寫。
		OutputStreamWriter fileWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
		fileWriter.write("奧特曼");
		fileWriter.close();
	}
}