[关闭]
@w460461339 2016-11-15T23:08:41.000000Z 字数 11596 阅读 1060

Java学习Day11 (登陆注册案例 以及超级多的流)

Java基础


今天学习了超级多的流以及用IO的方法重写了一下login&Regist的任务,发现还是挺多问题的。
下面一一介绍

1、LogIn&Regist

需求分析:
A:可以实现注册功能,并将用户存储至本地文件,下次仍可调用
B:实现注册功能,重名用户显示注册失败
C:实现登陆功能,用户名,密码均一致显示成功,否则显示失败

分包:
A:用户类包
|---用于构建用户类,以便今后调用来创建用户对象,存储存储用户信息。
B:用户功能接口包
|---定义可以针对用户类的功能接口,描述可以对用户类进行的操作。
C:用户功能实现包
|---实现对用户类的功能。
D:测试包
|---添加测试程序。

1.1用户类包
  1. package lr_User;
  2. //这个很简单,不解释了
  3. public class User {
  4. private String accout;
  5. private String password;
  6. public User() {
  7. super();
  8. // TODO Auto-generated constructor stub
  9. }
  10. public User(String accout, String password) {
  11. super();
  12. this.accout = accout;
  13. this.password = password;
  14. }
  15. public String getAccout() {
  16. return accout;
  17. }
  18. public void setAccout(String accout) {
  19. this.accout = accout;
  20. }
  21. public String getPassword() {
  22. return password;
  23. }
  24. public void setPassword(String password) {
  25. this.password = password;
  26. }
  27. @Override
  28. public String toString() {
  29. return "User [accout=" + accout + ", password=" + password + "]";
  30. }
  31. }
1.2用户功能接口包
  1. package lr_function;
  2. import lr_User.User;
  3. //定义方法的名称,参数类型,访问属性等。但不包含具体实现
  4. public interface User_function {
  5. //登陆方法,成功返回true,失败返回false
  6. public abstract boolean login(String account,String password);
  7. //注册方法,成功返回true,失败返回false
  8. public abstract boolean regist(User myuser);
  9. }
1.3用户功能实现包
  1. package lr_function_impl;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.File;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileReader;
  7. import java.io.FileWriter;
  8. import java.io.IOException;
  9. import lr_User.User;
  10. import lr_function.User_function;
  11. public class User_funciton_impl implements User_function{
  12. private static File file=new File("account.txt");
  13. //静态代码块,在调用该类的时候仅且运行一次。用来创建存储数据的文件。
  14. static{
  15. try {
  16. if(!file.exists()){
  17. file.createNewFile();
  18. }
  19. } catch (IOException e) {
  20. System.out.println("内存不足,初始文件失败");
  21. //e.printStackTrace();
  22. }
  23. }
  24. //实现登陆方法
  25. @Override
  26. public boolean login(String account, String password) {
  27. boolean flag=false;
  28. try {
  29. //按行得到account.txt中的数据
  30. BufferedReader br=new BufferedReader(
  31. new FileReader("account.txt"));
  32. String line=null;
  33. while((line=br.readLine())!=null){
  34. //以“=“为分割标志将数据分割
  35. String[] acc_pass=line.split("=");
  36. //比较用户名和账户
  37. if(acc_pass[0].equals(account)&&acc_pass[1].equals(password)){
  38. System.out.println("登陆成功");
  39. flag=true;
  40. }
  41. }
  42. } catch (FileNotFoundException e) {
  43. // TODO Auto-generated catch block
  44. System.out.println("文件不存在");
  45. //e.printStackTrace();
  46. } catch (IOException e) {
  47. // TODO Auto-generated catch block
  48. System.out.println("登录失败");
  49. //e.printStackTrace();
  50. }
  51. return flag;
  52. }
  53. @SuppressWarnings("finally")
  54. @Override
  55. public boolean regist(User myuser) {
  56. boolean flag=false;
  57. BufferedWriter bw=null;
  58. BufferedReader br=null;
  59. try {
  60. //判断用户名是否重复
  61. br=new BufferedReader(new FileReader("account.txt"));
  62. String line = null;
  63. while((line=br.readLine())!=null){
  64. String[] acc_pass=line.split("=");
  65. if(acc_pass[0].equals(myuser.getAccout())){
  66. System.out.println("用户名重复");
  67. return flag=false;
  68. }
  69. }
  70. } catch (IOException e1) {
  71. // TODO Auto-generated catch block
  72. System.out.println("IOException");
  73. //e1.printStackTrace();
  74. }
  75. try {
  76. //写入新的用户
  77. br=new BufferedReader(new FileReader("account.txt"));
  78. bw=new BufferedWriter(new FileWriter("account.txt",true));
  79. bw.write(myuser.getAccout()+"="+myuser.getPassword());
  80. bw.newLine();
  81. bw.flush();
  82. System.out.println("注册成功");
  83. flag=true;
  84. } catch (IOException e) {
  85. // TODO Auto-generated catch block
  86. System.out.println("注册失败");
  87. flag=false;
  88. //e.printStackTrace();
  89. }finally{
  90. if(bw!=null){
  91. try {
  92. bw.close();
  93. } catch (final IOException e) {
  94. System.out.println("释放资源失败");
  95. //e.printStackTrace();
  96. }
  97. }
  98. return flag;
  99. }
  100. }
  101. }
1.4测试包
  1. package lr_test;
  2. import java.util.Scanner;
  3. import lr_User.User;
  4. import lr_function_impl.User_funciton_impl;
  5. public class LogRegTest {
  6. /**
  7. * @param args
  8. */
  9. public static void main(String[] args) {
  10. User_funciton_impl usefun=new User_funciton_impl();
  11. Scanner sc=new Scanner(System.in);
  12. String account=null;
  13. String password=null;
  14. for(int i=1;i<6;i++){
  15. account=sc.nextLine();
  16. password=sc.nextLine();
  17. User myuser=new User(account,password);
  18. usefun.regist(myuser);
  19. }
  20. boolean flag=false;
  21. do{
  22. account=sc.nextLine();
  23. password=sc.nextLine();
  24. flag=usefun.login(account, password);
  25. if(!flag){
  26. System.out.println("用户名或者密码不对");
  27. }
  28. }while(!flag);
  29. }
  30. }

2.数据操作流(操作基本类型数据的流)(理解)

(1)可以操作基本类型的数据
八种基本数据类型,int,byte,long,char,short,double,float,boolean
(2)流对象名称
DataInputStream
DataOutputStream

  1. package trynewStream;
  2. import java.io.DataInputStream;
  3. import java.io.DataOutputStream;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.IOException;
  7. public class DataStreamDemo {
  8. public static void main(String[] args) throws IOException {
  9. //注意,只能直接操作8种基本数据类型,String之类的就不行了。
  10. //仅有读写配对才能顺利读写,不然报错
  11. DataOutputStream dos=new DataOutputStream(
  12. new FileOutputStream("datademo.txt"));
  13. DataInputStream dis=new DataInputStream(
  14. new FileInputStream("datademo.txt"));
  15. //写的时候写int
  16. dos.writeInt(10);
  17. dos.close();
  18. //读的时候就要用int读
  19. System.out.println(dis.readInt());
  20. dis.close();
  21. }
  22. }

3.内存操作流(理解)

(1)有些时候我们操作完毕后,未必需要产生一个文件,就可以使用内存操作流。意思就是说把产生的东西丢到内存中,然后从内存中拿出来。多用于临时文件存储。
(2)三种
字节数组: A:ByteArrayInputStream,ByteArrayOutputStream
字符数组: B:CharArrayReader,CharArrayWriter
字符串 : C:StringReader,StringWriter
就演示下字符数组的好了= - 不好玩= -

  1. package trynewStream;
  2. import java.io.CharArrayReader;
  3. import java.io.CharArrayWriter;
  4. import java.io.IOException;
  5. public class CharArrayReaderDemo {
  6. public static void main(String[] args)throws IOException {
  7. // TODO Auto-generated method stub
  8. CharArrayWriter caw=new CharArrayWriter();
  9. char[] ca={97,98,99,100};
  10. char[] ca2=new char[4];
  11. caw.write(ca);
  12. CharArrayReader car=new CharArrayReader(ca);
  13. car.read(ca2);
  14. System.out.println(ca2);
  15. }
  16. }

4:打印流(掌握)

(1)字节打印流,字符打印流
PrintStream,PritnWriter
(2)特点:
A:只操作目的地,不操作数据源
B:可以操作任意类型的数据
C:如果启用了自动刷新,在调用println()方法的时候,能够换行并刷新
D:可以直接操作文件
问题:哪些流可以直接操作文件呢?
看API,如果其构造方法能够同时接收File和String类型的参数,一般都是可以直接操作文件的
(3)复制文本文件

  1. package trynewStream;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.FileReader;
  6. import java.io.IOException;
  7. import java.io.PrintStream;
  8. public class PrintDemo {
  9. public static void main(String[] args)throws IOException {
  10. //封装数据源
  11. BufferedReader br=new BufferedReader(
  12. new FileReader("account.txt"));
  13. //封装目的地
  14. PrintStream ps=new PrintStream(new FileOutputStream(
  15. new File("copy.txt")),true);
  16. String line=null;
  17. while((line=br.readLine())!=null){
  18. ps.println(line);//直接完成写入,换行,刷新三个动作
  19. }
  20. br.close();
  21. ps.close();
  22. }
  23. }

5.标准输入输出流(理解)

其实就这么理解,标准输入流使用BufferedWriter实现的,标准输出流使用PrintSteram实现的。
(1)System类下面有这样的两个字段
in 标准输入流
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:原理

  1. System.out.println("helloworld");
  2. PrintStream ps = System.out;
  3. ps.println("helloworld");
    B:把System.out用字符缓冲流包装一下使用
  1. BufferedWriter bw = new BufferedWriter(
  2. new OutputStreamWriter(System.out));

6随机访问流(理解)

(1)可以按照文件指针的位置写数据和读数据。
RandomAccessFile();这货可读可写啊~~
(2)案例:
A:写数据
B:读数据
C:获取和改变文件指针的位置

  1. package trynewStream;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.RandomAccessFile;
  5. public class RandomStreamDemo {
  6. public static void main(String[] args) throws IOException{
  7. RandomAccessFile raf=new RandomAccessFile(new File("account.txt"), "rw");
  8. System.out.println(raf.readLine()+
  9. "---"+raf.getFilePointer());
  10. System.out.println(raf.readLine()+
  11. "---"+raf.getFilePointer());
  12. System.out.println(raf.readLine()+
  13. "---"+raf.getFilePointer());
  14. //文件指针重新指到18的位置上,再次读取后,最后一行又被读了
  15. raf.seek(18);
  16. System.out.println(raf.readLine()+
  17. "---"+raf.getFilePointer());
  18. }
  19. }

7.合并流(理解)

(1)把多个输入流的数据写到一个输出流中。
(2)构造方法:
A:SequenceInputStream(InputStream s1, InputStream s2)
B:SequenceInputStream(Enumeration e)

  1. import java.io.BufferedOutputStream;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.SequenceInputStream;
  7. public class SequenceStreamDemo {
  8. public static void main(String[] args)throws IOException {
  9. //封装数据源
  10. SequenceInputStream sis=new SequenceInputStream(
  11. new FileInputStream("account.txt"),
  12. new FileInputStream("datademo.txt"));
  13. //封装目的地
  14. BufferedOutputStream bos=new BufferedOutputStream(
  15. new FileOutputStream(new File("copy2.txt")));
  16. //复制
  17. byte[] bys=new byte[1024];
  18. int len=0;
  19. while((len=sis.read(bys))!=-1){
  20. bos.write(bys, 0, len);
  21. }
  22. //释放资源,关闭
  23. sis.close();
  24. bos.close();
  25. }
  26. }

写不动了,抄了一遍代码,这个说白了就是用vector存储所有要复制的流,然后一起输出。

  1. import java.io.BufferedOutputStream;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.SequenceInputStream;
  7. import java.util.Enumeration;
  8. import java.util.Vector;
  9. /*
  10. * 以前的操作:
  11. * a.txt -- b.txt
  12. * c.txt -- d.txt
  13. * e.txt -- f.txt
  14. *
  15. * 现在想要:
  16. * a.txt+b.txt+c.txt -- d.txt
  17. */
  18. public class SequenceInputStreamDemo2 {
  19. public static void main(String[] args) throws IOException {
  20. // 需求:把下面的三个文件的内容复制到Copy.java中
  21. // ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java
  22. // SequenceInputStream(Enumeration e)
  23. // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。
  24. // Enumeration<E> elements()
  25. Vector<InputStream> v = new Vector<InputStream>();
  26. InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
  27. InputStream s2 = new FileInputStream("CopyFileDemo.java");
  28. InputStream s3 = new FileInputStream("DataStreamDemo.java");
  29. v.add(s1);
  30. v.add(s2);
  31. v.add(s3);
  32. Enumeration<InputStream> en = v.elements();
  33. SequenceInputStream sis = new SequenceInputStream(en);
  34. BufferedOutputStream bos = new BufferedOutputStream(
  35. new FileOutputStream("Copy.java"));
  36. // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
  37. byte[] bys = new byte[1024];
  38. int len = 0;
  39. while ((len = sis.read(bys)) != -1) {
  40. bos.write(bys, 0, len);
  41. }
  42. bos.close();
  43. sis.close();
  44. }
  45. }

8.序列化流(理解)

主要目的就是直接往流中添加对象
(1)可以把对象写入文本文件或者在网络中传输
(2)如何实现序列化呢?
让被序列化的对象所属类实现序列化接口。
该接口是一个标记接口。没有功能需要实现。
(3)注意问题:
把数据写到文件后,在去修改类会产生一个问题。
如何解决该问题呢?
在类文件中,给出一个固定的序列化id值。
而且,这样也可以解决黄色警告线问题
(4)面试题:
什么时候序列化?
如何实现序列化?
什么是反序列化?

  1. package cn.itcast_08;
  2. import java.io.FileReader;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.io.Reader;
  6. import java.io.Writer;
  7. import java.util.Properties;
  8. /*
  9. * 这里的集合必须是Properties集合:
  10. * public void load(Reader reader):把文件中的数据读取到集合中
  11. * public void store(Writer writer,String comments):把集合中的数据存储到文件
  12. *
  13. * 单机版游戏:
  14. * 进度保存和加载。
  15. * 三国群英传,三国志,仙剑奇侠传...
  16. *
  17. * 吕布=1
  18. * 方天画戟=1
  19. */
  20. public class PropertiesDemo3 {
  21. public static void main(String[] args) throws IOException {
  22. // myLoad();
  23. myStore();
  24. }
  25. private static void myStore() throws IOException {
  26. // 创建集合对象
  27. Properties prop = new Properties();
  28. prop.setProperty("林青霞", "27");
  29. prop.setProperty("武鑫", "30");
  30. prop.setProperty("刘晓曲", "18");
  31. //public void store(Writer writer,String comments):把集合中的数据存储到文件
  32. Writer w = new FileWriter("name.txt");
  33. prop.store(w, "helloworld");
  34. w.close();
  35. }
  36. private static void myLoad() throws IOException {
  37. Properties prop = new Properties();
  38. // public void load(Reader reader):把文件中的数据读取到集合中
  39. // 注意:这个文件的数据必须是键值对形式
  40. Reader r = new FileReader("prop.txt");
  41. prop.load(r);
  42. r.close();
  43. System.out.println("prop:" + prop);
  44. }
  45. }
  1. import java.io.Serializable;
  2. /*
  3. * NotSerializableException:未序列化异常
  4. *
  5. * 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
  6. * 该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。
  7. *
  8. * java.io.InvalidClassException:
  9. * cn.itcast_07.Person; local class incompatible:
  10. * stream classdesc serialVersionUID = -2071565876962058344,
  11. * local class serialVersionUID = -8345153069362641443
  12. *
  13. * 为什么会有问题呢?
  14. * Person类实现了序列化接口,那么它本身也应该有一个标记值。
  15. * 这个标记值假设是100。
  16. * 开始的时候:
  17. * Person.class -- id=100
  18. * wirte数据: oos.txt -- id=100
  19. * read数据: oos.txt -- id=100
  20. *
  21. * 现在:
  22. * Person.class -- id=200
  23. * wirte数据: oos.txt -- id=100
  24. * read数据: oos.txt -- id=100
  25. * 我们在实际开发中,可能还需要使用以前写过的数据,不能重新写入。怎么办呢?
  26. * 回想一下原因是因为它们的id值不匹配。
  27. * 每次修改java文件的内容的时候,class文件的id值都会发生改变。
  28. * 而读取文件的时候,会和class文件中的id值进行匹配。所以,就会出问题。
  29. * 但是呢,如果我有办法,让这个id值在java文件中是一个固定的值,这样,你修改文件的时候,这个id值还会发生改变吗?
  30. * 不会。现在的关键是我如何能够知道这个id值如何表示的呢?
  31. * 不用担心,你不用记住,也没关系,点击鼠标即可。
  32. * 你难道没有看到黄色警告线吗?
  33. *
  34. * 我们要知道的是:
  35. * 看到类实现了序列化接口的时候,要想解决黄色警告线问题,就可以自动产生一个序列化id值。
  36. * 而且产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。
  37. *
  38. * 注意:
  39. * 我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢?
  40. * 使用transient关键字声明不需要序列化的成员变量
  41. */
  42. public class Person implements Serializable {
  43. private static final long serialVersionUID = -2071565876962058344L;
  44. private String name;
  45. // private int age;
  46. private transient int age;
  47. // int age;
  48. public Person() {
  49. super();
  50. }
  51. public Person(String name, int age) {
  52. super();
  53. this.name = name;
  54. this.age = age;
  55. }
  56. public String getName() {
  57. return name;
  58. }
  59. public void setName(String name) {
  60. this.name = name;
  61. }
  62. public int getAge() {
  63. return age;
  64. }
  65. public void setAge(int age) {
  66. this.age = age;
  67. }
  68. @Override
  69. public String toString() {
  70. return "Person [name=" + name + ", age=" + age + "]";
  71. }
  72. }

10.NIO(了解)

(1)JDK4出现的NIO,对以前的IO操作进行了优化,提供了效率。但是大部分我们看到的还是以前的IO
(2)JDK7的NIO的使用
Path:路径
Paths:通过静态方法返回一个路径
Files:提供了常见的功能
复制文本文件
把集合中的数据写到文本文件

写不动了…睡觉= -

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注