天天看点

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:提供了常见的功能
			复制文本文件
			把集合中的数据写到文本文件