天天看點

Java基礎知識24——IO流day04-Properties集合&序列化流和反序列化流&列印流&commons-IO列印流序列化流和反序列化流Properties集合commons-IOProperties、序列化流、列印流大總結

列印流

Java基礎知識24——IO流day04-Properties集合&序列化流和反序列化流&列印流&commons-IO列印流序列化流和反序列化流Properties集合commons-IOProperties、序列化流、列印流大總結
* 列印流
 * 位元組列印流	PrintStream
 * 字元列印流	PrintWriter
 * 
 * 列印流的特點:
 * A:隻有寫資料,沒有讀資料。隻能操作目的地,不能操作資料源
 * B:可以操作任意類型的資料
 * 			print()
 * 			println()
 * C:如果啟動了自動重新整理,能夠自動重新整理
 * 	PrintWrite bw = new PrintWriter(new FileWriter/FileOutPutStream("pw2.txt"),true)
 * 			調用println()的方法才可以
 * 			這個時候不僅僅自動重新整理了,還實作了資料的換行
 * 		println()
 * 		等價于
 * 		bw.write();
 * 		bw.newLine();
 * 		bw.flush();
 * D:該流是可以直接操作文本檔案的
 * 		哪些對象是可以直接操作文本檔案的呢?
 * 		FileInputStream
 * 		FileOutputStream
 * 		FileReader
 * 		FileWriter
 * 		PrintWriter
 * 		printStream
 * 		看API,查流對象的構造方法,如果同時有File類型和String類型的參數,一般來說就是可以直接操作檔案的
 * 
 * 		流:
 * 			基本流:就是能夠直接讀寫檔案的
 * 			進階流:在基本流操作基礎上提供了一些其他的功能
           

序列化流和反序列化流

Java基礎知識24——IO流day04-Properties集合&序列化流和反序列化流&列印流&commons-IO列印流序列化流和反序列化流Properties集合commons-IOProperties、序列化流、列印流大總結
* 序列化:把對象按照流一樣的方式存入文本檔案或者在網絡中傳輸。對象----》流資料(ObjectOutputStream)
 * 反序列化:把文本檔案中的流對象資料或者網絡中的流對象資料還原成對象。流資料---》對象(ObjectInputStream)
 * 
 * NotSerializableException:未序列化異常 
 * 類通過實作 java.io.Serializable 
 * 接口以啟用其序列化功能。未實作此接口的類将無法使其任何狀态序列化或反序列化。
 * 該接口居然沒有任何方法,類似于這種沒有方法的接口被稱為标記接口。
 * 
 * local class incompatible: 
 * stream classdesc serialVersionUID = -8036188228921520309, 
 * local class serialVersionUID = -3432617418350035952
 * 
 * 為什麼有問題呢?
 * 	Person類實作了序列化接口,那麼它本身也應該有一個标記值。
 * 	這個标記值假設是100。
 * 	開始的時候:
 * 	Person.class -- id=100
 * 	write資料:oos.txt -- id = 100
 * 	read資料:oos.txt -- id = 100
 * 	現在:
 * 	Person.class -- id = 200
 * 	write資料:oos.txt -- id =100
 * 	read資料:oos.txt -- id = 100
 * 我們實際開發中,可能需要使用以前寫過的資料,不能重新寫入。怎麼辦呢?
 * 回想一下原因是因為他們的id值不比對。
 * 每次修改java檔案的内容的時候,class檔案的id值都會發生變化
 * 而讀取檔案的時候,會和class檔案中的id值進行比對。是以就會出問題。
 * 但是呢,如果我有辦法讓這個id值在java檔案中是一個固定的值,這樣,你修改檔案的時候,
 * 這個id值就不會發生改變,現在的關鍵是我如何知道這個id值如何表示呢?
 * 不用擔心,你不用記住也沒關系,滑鼠點選即可。
 * 你難道沒有看到黃色警告線嗎?
 * 
 * 我們要知道的是:
 * 	看到類實作序列化接口的時候,要想解決黃色警告線問題,就可以自動産生一個序列化id值。
 * 	而且産生這個值以後,我們對類進行任何改動,它讀取以前的資料是沒問題的。
 * 
 * 注意:
 * 		我一個類中可能有很多的成員變量,有些我不想進行序列化,請問該怎麼辦呢
 * 		使用transient關鍵字聲明不需要序列化的成員變量
           

Properties集合

Java基礎知識24——IO流day04-Properties集合&序列化流和反序列化流&列印流&commons-IO列印流序列化流和反序列化流Properties集合commons-IOProperties、序列化流、列印流大總結
* Properties:屬性集合類,是一個可以和IO流相結合使用的集合類。
 * Properties可儲存在流中或從流中加載。屬性清單中每個鍵及其對應值都是一個字元串。
 * Properties是Hashtable的子類,說明是一個Map集合
 * Properties屬性集合類的特有功能:
 * public Object setProperty(String key, String value):添加元素
 * public String getProperty(String key):擷取元素
 * public Set<String> stringPropertyNames():擷取所有鍵的集合
 * 
 * 這裡的集合必須是Properties集合
 * public void load(Reader reader):把檔案中的資料讀取到集合中
 * 注意:這個檔案的資料必須是鍵值對形式
 * public void store(Writer writer,String comments):把集合中的資料存儲到檔案
           

commons-IO

Java基礎知識24——IO流day04-Properties集合&amp;序列化流和反序列化流&amp;列印流&amp;commons-IO列印流序列化流和反序列化流Properties集合commons-IOProperties、序列化流、列印流大總結

Properties、序列化流、列印流大總結

1:登入注冊IO版本案例(掌握)	
	cn.itcast.pojo User
		class User {//【代碼實作】
			//成員變量
			private String username;
			private String password;
			//構造方法
			public User(){}//無參構造
			public User(String username,String password){	//滿帶參構造
				this.username = username;
				this.password = password;
			}
			//成員方法setXxx()/getXxx()
			public void setUsername(String username){
				this.username = username;
			}
			public String getUsername(){
				return username;
			}
			public void setPassword(String password){
				this.password = password;
			}
			public String getPassword(){
				return password;
			}
		}
	cn.itcast.dao UserDao
		public interface UserDao {//【代碼實作】
			public abstract boolean isLogin(String username,String password);
			public abstract void regist(User user);
		}
	cn.itcast.dao.impl UserDaoImpl(實作我不管)
		public class UserDaoImpl implements UserDao {//【代碼實作】
			private static File file = new File("user.txt");
			static {
				try {
					file.createNewFile();
				} catch (IOException e) {
					System.out.println("使用者資訊檔案建立失敗");
				}
			}

			@Override
			public boolean isLogin(String username, String password) {
				BufferedReader br = null;
				boolean isRight = false;
				try {
					br = new BufferedReader(new FileReader(file));
					String line;
					while ((line = br.readLine()) != null) {
						String[] arr = line.split("=");
						if (arr[0].equals(username) && arr[1].equals(password)) {
							isRight = true;
							break;
						}
					}
				} catch (FileNotFoundException e) {
					System.out.println("使用者資訊檔案找不到,登入失敗");
				} catch (IOException e) {
					System.out.println("使用者登入失敗");
				} finally {
					if (br != null) {
						try {
							br.close();
						} catch (IOException e) {
							System.out.println("使用者登入資訊釋放資源關閉失敗");
						}
					}
				}

				return isRight;
			}

			@Override
			public void regist(User user) {
				BufferedWriter bw = null;
				try {
					bw = new BufferedWriter(new FileWriter(file, true));
					bw.write(user.getUsername() + "=" + user.getPassword());
					bw.newLine();
					bw.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					// e.printStackTrace();
					System.out.println("使用者注冊資訊失敗");
				} finally {
					if (bw != null) {
						try {
							bw.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							// e.printStackTrace();
							System.out.println("注冊資訊釋放資源失敗");
						}
					}
				}
			}
		}

	cn.itcast.game GuessNumber
		public class GuessNumber{//【代碼實作】
			public static void start(){
				int number = (int)(Math.random()*100+1);
				int count = 0;
				while(true){
					Scanner sc = new Scanner(System.in);
					System.out.println("請輸入你猜的數字:");
					int guessNumber = sc.nextInt();
					count++;
					if(number > guessNumber){
						System.out.println("你猜的數字"+guessNumber+"小了");
					}else if(number<guessNumber){
						System.out.println("你猜的數字"+guessNumber+"大了");
					}else{
						System.out.println("恭喜你猜了"+count+"次猜中了");
						break;
					}
				}	
			}
		}
	cn.itcast.test	UserTest
		public class UserTest {//【代碼實作】
			public static void main(String[] args) {
				while (true) {
					// 歡迎界面,給出選擇項
					System.out.println("------o------歡迎光臨------------");
					System.out.println("1.登入");
					System.out.println("2.注冊");
					System.out.println("3.退出");
					System.out.println("------------------------------");
					Scanner sc = new Scanner(System.in);
					// 鍵盤錄入選擇,根據選擇做不同的操作
					System.out.println("請輸入你的選擇(1-3):");
					// 為了後面的錄入資訊的友善,我所有的資料錄入全部用字元接收
					String choice = sc.nextLine();
					// switch多個地方要使用,我就定義到外面
					UserDao ud = new UserDaoImpl();
					switch (choice) {
						case "1":
							System.out.println("------------登入界面------------");
							System.out.println("請輸入使用者名:");
							String username = sc.nextLine();
							System.out.println("請輸入密碼:");
							String password = sc.nextLine();
							// UserDao ud = new UserDaoImpl();
							boolean success = ud.isLogin(username, password);
							if (success) {
								System.out.println("登陸成功,可以開始玩猜數字遊戲了");
								System.out.println("你玩嗎?y/n");
								while (true) {
									String s = sc.nextLine();
									if ("y".equalsIgnoreCase(s)) {
										GuessNumber.start();
										System.out.println("你還玩嗎?y/n");
									} else {
										break;
									}
								}
								System.out.println("謝謝使用,歡迎下次再來!");
								System.exit(0);
								// break;//這裡寫break,結束的是switch
							} else {
								System.out.println("使用者名或密碼錯誤,登陸失敗");
							}
							break;
						case "2":
							System.out.println("------------注冊界面------------");
							System.out.println("請輸入使用者名:");
							String newUsername = sc.nextLine();
							System.out.println("請輸入密碼:");
							String newPassword = sc.nextLine();
							// 把使用者名和密碼封裝到對象中
							User user = new User();
							user.setUsername(newUsername);
							user.setPassword(newPassword);
							// 調用注冊功能
							// 多态
							// UserDao ud = new UserDaoImpl();
							// 具體類使用
							// UserDao use = new UserDaoImpl();
							ud.regist(user);
							System.out.println("注冊成功");
							break;
						case "3":
						default:
							System.out.println("謝謝使用,再見!");
							System.exit(0);
							break;
						}
				}
			}
		}

2:資料操作流(操作基本類型資料的流)(了解)
	(1)可以操作基本類型的資料【byte,short,char,boolean,int,long,double,float】
	(2)流對象名稱	
		DataInputStream		readXxx();
		DataOutputStream	writeXxx();

3:記憶體操作流(了解)
	(1)有些時候我們操作完畢後,未必需要産生一個檔案,就可以使用記憶體操作流。
	(2)三種
		A:ByteArrayInputStream,ByteArrayOutputStream	位元組數組操作流【參數是位元組數組】
		B:CharArrayReader,CharArrayWriter				字元數組操作流【參數是字元數組】
		C:StringReader,StringWriter						字元串數組操作流【參數是字元串數組】

4:列印流(掌握)
	(1)位元組列印流【PrintStream】,字元列印流【PrintWriter】
	(2)特點:
		A:隻操作目的地,不操作資料源
		B:可以操作任意類型的資料
		C:如果啟用了自動重新整理,在調用println()方法的時候,能夠換行并重新整理
		D:可以直接操作檔案
			問題:哪些流可以直接操作檔案呢?
			看API,如果其構造方法能夠同時接收File和String類型的參數,一般都是可以直接操作檔案的
	(3)複制文本檔案
		BufferedReader br = new BufferedReader(new FileReader("a.txt"));
		PrintWriter pw = new PrintWriter(new FileWriter("b.txt"),true);
		
		String line = null;
		while((line=br.readLine())!=null) {
			pw.println(line);
		}
		
		pw.close();
		br.close();
			
5:标準輸入輸出流(了解)
	(1)System類下面有這樣的兩個字段
		public static final InputStream in; 	标準輸入流	InputStream is = System.in;
		public static final OutputStream out; 	标準輸出流	OutputStream os = System.out;
	(2)三種鍵盤錄入方式
		A:main方法的args接收參數
		B:System.in通過BufferedReader進行包裝
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		C:Scanner
			Scanner sc = new Scanner(System.in);
	(3)輸出語句的原理和如何使用字元流輸出資料
		A:原理
			System.out.println("helloworld");
			等價于
			PrintStream ps = System.out;
			ps.println("helloworld");
			
		B:把System.out用字元緩沖流包裝一下使用
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

6:随機通路流(了解)【RandomAccessFile】
	(1)可以按照檔案指針的位置寫資料和讀資料。
	(2)案例:
		A:寫資料	write()
		B:讀資料	read()
		C:擷取和改變檔案指針的位置	long getFilePointer()和void seek(long pos)

7:合并流(了解)
	(1)把多個輸入流的資料寫到一個輸出流中。
	(2)構造方法:
		A:SequenceInputStream(InputStream s1, InputStream s2) 
		B:SequenceInputStream(Enumeration<? extends InputStream> e) 
			案例:
		 * public SequenceInputStream(Enumeration<? extends InputStream> e)
		 * 通過簡單的回顧我們知道了Enumeration是Vector中的一個方法的傳回值類型。
		 * Enumeration<E> elements()
		 * 
		 * Vector<InputStream> v = new Vector<InputStream>();
		 * InputStream is1 = new FileInputStream("copy2.java");
		 * ...
		 * v.addElement(is1);
		 * ...
		 * Enumeration<InputStream> en= v.elements();
		 * SequenceInputStream sis = new SequenceInputStream(en);
		 * BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("多合并.txt"));
		 *		byte[] bytes = new byte[4096];
		 *		int by;
		 *		while((by = sis.read(bytes))!=-1){
		 *			bos.write(bytes, 0, by);
		 *			bos.flush();
		 *		}
		 *		bos.close();
		 *		sis.close();

8:序列化流(了解)【ObjectInputStream&&ObjectOutputStream】
	(1)可以把對象寫入文本檔案或者在網絡中傳輸
	(2)如何實作序列化呢?
		讓被序列化的對象所屬類實作序列化接口。
		該接口是一個标記接口。沒有功能需要實作。
	(3)注意問題:
		把資料寫到檔案後,如果再去修改類會産生一個問題。
		如何解決該問題呢?
			在類檔案中,給出一個固定的序列化id值。
			而且,這樣也可以解決黃色警告線問題
		如果對象中的某個屬性不想被序列化,加關鍵字transient修飾,該對象就不能被序列化了。
	(4)面試題:
		什麼是序列化?	将對象------轉換成-----》流資料
		如何實作序列化?	讓被序列化的對象所屬類去實作序列化接口
		什麼是反序列化?	将流資料------轉換成-----》對象

9:Properties(了解)
	(1)是一個集合類,Hashtable的子類
	(2)特有功能
		A:public Object setProperty(String key,String value):添加元素
		B:public String getProperty(String key):根據鍵擷取值
		C:public Set<String> stringPropertyNames():擷取所有的鍵
			案例:
				//建立集合對象
				Properties prop = new Properties();
				//添加元素
				prop.setProperty("張三", "30");
				prop.setProperty("李四", "40");
				prop.setProperty("王五", "50");
				
				Set<String> set = prop.stringPropertyNames();
				for (String key : set) {
					String value = prop.getProperty(key);
					System.out.println(key+"-----"+value);
				}
	(3)和IO流結合的方法
		把鍵值對形式的文本檔案内容加載到集合中
		public void load(Reader reader)
		public void load(InputStream inStream)

		把集合中的資料存儲到文本檔案中
		public void store(Writer writer,String comments)
		public void store(OutputStream out,String comments)
	(4)案例:
		A:根據給定的檔案判斷是否有鍵為"lisi"的,如果有就修改其值為100
					//A:把檔案中的資料加載到集合中
					//建立集合對象
					Properties prop = new Properties();
					//建立字元輸入流對象
					Reader r = new FileReader("prop.txt");
					//将檔案中的資料加載到集合
					prop.load(r);
					//釋放資源
					r.close();
					
					//B:周遊集合,擷取得到每一個鍵
					Set<String> set = prop.stringPropertyNames();
					for (String key : set) {
						//C:判斷鍵是否有“lisi”的,如果有就修改其值為“100”
						if("lisi".equals(key)){
							prop.setProperty(key, "100");
						}
					}
					
					//D:把集合中的資料重新存儲到檔案中
					Writer w = new FileWriter("prop.txt");
					prop.store(w, null);
					w.close();
		B:寫一個程式實作控制猜數字小遊戲程式不能玩超過5次
					// 把鍵值對形式的文本檔案内容加載到集合中
					Reader r = new FileReader("count.txt");
					Properties prop = new Properties();
					prop.load(r);
					r.close();

					String value = prop.getProperty("count");
					int number = Integer.parseInt(value);
					if(number>5){
						System.out.println("遊戲試玩已結束,請付費。");
						System.exit(0);
					}else{
						number++;
						GuessNumber.start();
						//把集合中的資料存儲到文本檔案中
						prop.setProperty("count", String.valueOf(number));
						Writer w = new FileWriter("count.txt");
						prop.store(w, null);
						w.close();
					}

10:NIO(了解)
	(1)JDK4出現的NIO,對以前的IO操作進行了優化,提供了效率。但是大部分我們看到的還是以前的IO
	(2)JDK7的NIO的使用	
		Path:路徑
		Paths:通過靜态方法傳回一個路徑
		Files:提供了常見的功能
			複制文本檔案
			把集合中的資料寫到文本檔案
           

繼續閱讀