Java第09次实验(IO流)

0. 字节流与二进制文件

  1. 使用DataOutputStream与FileOutputStream将Student对象写入二进制文件student.data
    • 二进制文件与文本文件的区别
    • try...catch...finally注意事项
    • 使用try..with...resouces关闭资源
  2. 使用DataInputStream与FileInputStream从student.data中读取学生信息并组装成对象

我的代码

  1 class Student {
  2     private int id;
  3     private String name;
  4     private int age;
  5     private double grade;    
  6     public Student(){
  7         
  8     }
  9     public Student(int id, String name, int age, double grade) {
 10         this.id = id;
 11         this.setName(name);
 12         this.setAge(age);
 13         this.setGrade(grade);
 14     }
 15     public int getId() {
 16         return id;
 17     }
 18     public void setId(int id) {
 19         this.id = id;
 20     }
 21     public String getName() {
 22         return name;
 23     }
 24     public void setName(String name) {
 25         if (name.length()>10){
 26             throw new IllegalArgumentException("name's length should <=10 "+name.length());
 27         }
 28         this.name = name;
 29     }
 30     public int getAge() {
 31         return age;
 32     }
 33     public void setAge(int age) {
 34         if (age<=0){
 35             throw new IllegalArgumentException("age should >0 "+age);
 36         }
 37         this.age = age;
 38     }
 39     public double getGrade() {
 40         return grade;
 41     }
 42     public void setGrade(double grade) {
 43         if (grade<0 || grade >100){
 44             throw new IllegalArgumentException("grade should be in [0,100] "+grade);
 45         }
 46         this.grade = grade;
 47     }
 48     @Override
 49     public String toString() {
 50         return "Student [id=" + id + ", name=" + name + ", age=" + age + ", grade=" + grade + "]";
 51     }
 52     
 53 }
 54  public class Main {
 55         public static void main(String[] args)
 56         {
 57             
 58             String fileName="d:\\student.data";
 59             try(DataOutputStream dos=new DataOutputStream(new FileOutputStream(fileName)))
 60             {
 61                 Student[] stu=new Student[3];
 62                 stu[0]=new Student(1,"zhangsan",19,65.0);
 63                 stu[1]=new Student(2,"lisi",19,75.0);
 64                 stu[2]=new Student(3,"wangwu",20,85.0);
 65                 for(Student stu1:stu) {
 66                     dos.writeInt(stu1.getId());
 67                     dos.writeUTF(stu1.getName());
 68                     dos.writeInt(stu1.getAge());
 69                     dos.writeDouble(stu1.getGrade());
 70                 }
 71                 
 72             } catch (FileNotFoundException e) {
 73                 // TODO Auto-generated catch block
 74                 e.printStackTrace();
 75                 System.out.println("1");
 76             } catch (IOException e) {
 77                 // TODO Auto-generated catch block
 78                 e.printStackTrace();
 79                 System.out.println("2");
 80             }
 81             try(DataInputStream dis=new DataInputStream(new FileInputStream(fileName)))
 82             {
 83                 while(dis!=null) {
 84                     int id=dis.readInt();
 85                     String name=dis.readUTF();
 86                     int age=dis.readInt();
 87                     double grade=dis.readDouble();
 88                     Student stu=new Student(id,name,age,grade);
 89                     System.out.println(stu);
 90                 }
 91                 
 92                 
 93             } catch (FileNotFoundException e) {
 94                 // TODO Auto-generated catch block
 95                 e.printStackTrace();
 96                 System.out.println("3");
 97             } catch (IOException e) {
 98                 // TODO Auto-generated catch block
 99                 e.printStackTrace();
100                 System.out.println("4");
101             }
102             
103         }

我的总结

在读取文件数据时while循环会报错,加入测试点后发现while循环多读了一次,

后将while(dis!=null)改成while(dis.available()!=0),问题解决

1. 字符流与文本文件:使用 PrintWriter(写),BufferedReader(读)

任务:

  1. 使用BufferedReader从编码为UTF-8的文本文件中读出学生信息,并组装成对象然后输出。
    • 中文乱码问题(FileReader使用系统默认编码方式读取文件,会产生乱码,可使用InputStreamReader解决)
    • String的split方法使用\\s+可以使用多个空格作为分隔符。
    • 进阶:修改Students.txt文件,在正确的数据行中间增加一些错误行(如,每行只有3个数据,或者应该是数字的地方放入其他字符),修改自己的程序,让起可以处理出错的行(报错但可以继续运行)。
  2. 编写public static ListreadStudents(String fileName);从fileName指定的文本文件中读取所有学生,并将其放入到一个List中
  3. 使用PrintWriter将Student对象写入文本文件,基础代码见后。注意:缓冲区问题。
  4. 使用ObjectInputStream/ObjectOutputStream读写学生对象。

我的代码

1.

 1  public class Main {
 2         public static void main(String[] args) throws IOException
 3         {
 4             String FileName="D:\\TSBrowserDownloads\\Students.txt";
 5             BufferedReader br = null;
 6             try {
 7                 br = new BufferedReader(new InputStreamReader(new FileInputStream(FileName),"UTF-8"));
 8                 String line = null;
 9                 while((line=br.readLine())!=null)
10                     System.out.println(line);
11             } finally{
12                 if (br!=null){
13                     br.close();
14                 }
15             }
16         }
17 
18     }

我的总结

默认方法打开读取会产生乱码

将模式读取方式改成"UTF-8"后显示正常

 

2.

 1 public static void ListreadStudents(String fileName){
 2             ArrayList<Student> StudentList=new ArrayList<Student>();
 3             BufferedReader br = null;
 4             try {
 5                 br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"UTF-8"));
 6                 while(br!=null) {
 7                     String line=br.readLine();
 8                     String[] stu=line.split("\\s+");
 9                     int id=Integer.parseInt(stu[0]);
10                     String name=stu[1];
11                     int age=Integer.parseInt(stu[2]);
12                     double grade=Double.parseDouble(stu[3]);
13                     Student Stu=new Student(id,name,age,grade);
14                     StudentList.add(Stu);          
15                 }                
16             } finally{
17                 if (br!=null){
18                     br.close();
19                 }
20             }
21 }

实验调试

刚开始本来想用和DataInputStream一样直接读,发现BufferedReader只用read和ReadLine方法,得用实验提到的"\\s+"的方法将读到的一整行用分隔符来分开,再用类型转换来读。

 

3.

2             String FileName="D:\\TSBrowserDownloads\\Students.txt";
3             PrintWriter pw=new PrintWriter(new OutputStreamWriter(new FileOutputStream(FileName,true),"UTF-8"));
4             pw.print("4 陈六 21 93");
5             pw.close();

我的总结

正确写入文件

 

4.

 1         String FileName="D:\\TSBrowserDownloads\\student.dat";
 2             try(
 3                     FileOutputStream fos=new FileOutputStream(FileName);
 4                     ObjectOutputStream oos=new ObjectOutputStream(fos))
 5                 {
 6                     Student ts=new Student(5,"asd",14,60);
 7                     oos.writeObject(ts);
 8                 }
 9                 catch (Exception e) {
10                     // TODO Auto-generated catch block
11                     e.printStackTrace();
12                 }
13                 try(
14                     FileInputStream fis=new FileInputStream(FileName);
15                     ObjectInputStream ois=new ObjectInputStream(fis))
16                 {
17                     Student newStudent =(Student)ois.readObject();
18                     System.out.println(newStudent);
19                 } catch (IOException e) {
20                     // TODO Auto-generated catch block
21                     e.printStackTrace();
22                 } catch (ClassNotFoundException e) {
23                     // TODO Auto-generated catch block
24                     e.printStackTrace();
25                 }

 

2. 缓冲流(结合使用JUint进行测试)

使用PrintWriter往文件里写入1千万行随机整数,范围在[0,10]。随机数种子设置为100.
然后从文件将每行读取出来转换成整数后相加。然后依次输出“个数 和 平均值(保留5位小数)”。
对比使用BufferedReader与使用Scanner从该文件中读取数据(只读取,不输出),使用哪种方法快?

    • 使用junit对比BufferedReaderScanner读文件的效率
    • 格式化输出:System.out.format。
    • 要使用Scanner的hasNextXXX方法来判断是否到文件尾,否则会抛异常。
    • Scanner的asNextXXX方法应与相对应的nextXXX方法配合使用,否则容易出。
    • 请删除fail("Not yet implemented");;并且在需要测试的方法上使用@Test进行标注。

写入文件代码

 1 String FILENAME = "test.txt";    
 2         double sum=0,aver;
 3         PrintWriter pw=null;
 4         try {
 5             pw = new PrintWriter(FILENAME);
 6             for(int i = 0;i<10000000;i++){//写入1千万行
 7             int r=new Random().nextInt(10);
 8             sum+=r;
 9             pw.println(r);
10             //System.out.println(r);
11         }
12         } catch (FileNotFoundException e) {
13             e.printStackTrace();
14         }finally{
15             pw.close();
16         }
17         aver=sum/10000000;
18         System.out.format("%.5f", aver);
19     }

 

使用JUint的代码

 

 1         public class test {
 2     @Test
 3         public void test() {
 4         String FILENAME = "test.txt";
 5         long begin = System.currentTimeMillis();
 6         Scanner scanner=null;
 7         try {
 8             scanner = new Scanner(new File(FILENAME));
 9             while(scanner.hasNextLine()){//只是读出每一行,不做任何处理
10                 scanner.nextLine();
11             }
12         } catch (FileNotFoundException e) {
13             e.printStackTrace();
14         }finally{
15             scanner.close();
16         }
17         long end = System.currentTimeMillis();
18         System.out.println("last "+(end-begin));
19         System.out.println("read using Scanner done");
20     }
21     @Test
22     public void Bufftest() {
23         String FILENAME = "test.txt";
24         long begin = System.currentTimeMillis();
25         BufferedReader br = null;
26         try {
27              br = new BufferedReader(new FileReader(new File(FILENAME)));
28             while(br.readLine()!=null){};//只是读出,不进行任何处理
29         } catch (FileNotFoundException e) {
30             e.printStackTrace();
31         } catch (IOException e) {
32             e.printStackTrace();
33         }finally{
34             try {
35                 br.close();
36             } catch (IOException e) {
37                 e.printStackTrace();
38             }
39         }
40         long end = System.currentTimeMillis();
41         System.out.println("last "+(end-begin));
42         System.out.println("read using BufferedReader done");
43     }
44 }

 

我的总结

可以明显对比出缓冲流BufferedReader的方法要比Scanner的方法快很多

 

 不使用JUint也可以在循环开始前后定义时间变量,最后相减也能得到运行所用时间

 

第2次实验

3. 字节流之对象流

结合使用ObjectOutputStream、ObjectInputStream与FileInputStream、FileOuputStream实现对Student对象的读写。
编写如下两个方法:

    • public static void writeStudent(List stuList)
    • public static List readStudents(String fileName)

 我的代码

 

 1 public static void writeStudent(List<Student> stuList)
 2     {
 3         String fileName="D:\\Student.dat";
 4         try (   FileOutputStream fos=new FileOutputStream(fileName);
 5                 ObjectOutputStream ois=new ObjectOutputStream(fos))
 6         {
 7             ois.writeObject(stuList);
 8             
 9         } 
10         catch (FileNotFoundException e) {
11             // TODO Auto-generated catch block
12             e.printStackTrace();
13         } catch (IOException e1) {
14             // TODO Auto-generated catch block
15             e1.printStackTrace();
16         }
17     }
18 public static List<Student> readStudents(String fileName)
19     {
20         List<Student> stuList=new ArrayList<>();
21         try (   FileInputStream fis=new FileInputStream(fileName);
22                 ObjectInputStream ois=new ObjectInputStream(fis))
23         {
24             stuList=(List<Student>)ois.readObject();
25         } 
26         catch (FileNotFoundException e) {
27             // TODO Auto-generated catch block
28             e.printStackTrace();
29         } catch (IOException e1) {
30             // TODO Auto-generated catch block
31             e1.printStackTrace();
32         } catch (ClassNotFoundException e) {
33             // TODO Auto-generated catch block
34             e.printStackTrace();
35         }
36         return stuList;
37     }   

 

5. 文件操作

编写一个程序,可以根据指定目录和文件名,搜索该目录及子目录下的所有文件,如果没有找到指定文件名,则显示无匹配,否则将所有找到的文件名与文件夹名显示出来。

    1. 编写public static void findFile(Path dir,String fileName)方法.
      以dir指定的路径为根目录,在其目录与子目录下查找所有和filename
      相同的文件名,一旦找到就马上输出到控制台。

我的代码

 

 1 if (args.length == 0) args = new String[] { ".." };
 2       try
 3       {
 4          File pathName = new File(args[0]);
 5          String[] fileNames = pathName.list();
 6 
 7          // enumerate all files in the directory
 8          for (int i = 0; i < fileNames.length; i++)
 9          {
10             File f = new File(pathName.getPath(), fileNames[i]);
11 
12             // if the file is again a directory, call the main method recursively
13             if (f.isDirectory())
14             {
15                 if(f.getName().contains(fileName)) {
16                     System.out.println(f.getCanonicalPath());
17                     main(new String[] { f.getPath() });
18                 }          
19             }
20          }
21       }
22       catch (IOException e)
23       {
24          e.printStackTrace();
25       }

我的总结

用了参考代码稍加修改,若文件名字包含fileName,则输出该文件的路径

 

6. 正则表达式

 

  1. 如何判断一个给定的字符串是否是10进制数字格式?尝试编程进行验证。
  2. 修改HrefMatch.java
    • 尝试匹配网页中的数字字符串
    • 尝试匹配网页中的图片字符串

1.

 1  Scanner sc=new Scanner(System.in);
 2             Pattern pattern=Pattern.compile("^-?[0-9]\\d*(\\.\\d+)?$");
 3             Matcher matcher=null;
 4             while(sc.hasNext())
 5             {
 6                 String str=sc.next();
 7                 matcher=pattern.matcher(str);
 8                 System.out.println(matcher.matches());
 9             }
10             sc.close();

 

2.

 1 try
 2       {
 3          // get URL string from command line or use default
 4          String urlString;
 5          if (args.length > 0) urlString = args[0];
 6          else urlString = "http://cec.jmu.edu.cn";
 7 
 8          // open reader for URL
 9         InputStreamReader in = new InputStreamReader(new URL(urlString).openStream());
10     //InputStreamReader in = new InputStreamReader(new FileInputStream("集美大学-计算机工程学院.htm"));
11          // read contents into string builder
12          StringBuilder input = new StringBuilder();
13          int ch;
14          while ((ch = in.read()) != -1)
15             input.append((char) ch);
16 
17          // search for all occurrences of pattern
18          String patternString = "<a\\s+href\\s*=\\s*(\"[^\"]*\"|[^\\s>]*)\\s*>";
19      String patternImgString = "[+-]?[0-9]+";
20      //String patternString = "[\u4e00-\u9fa5]";     //匹配文档中的所有中文
21          Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
22          Matcher matcher = pattern.matcher(input);
23 
24          while (matcher.find())
25          {
26             int start = matcher.start();
27             int end = matcher.end();
28             String match = input.substring(start, end);
29             System.out.println(match);
30          }
31       }
32       catch (IOException e)
33       {
34          e.printStackTrace();
35       }
36       catch (PatternSyntaxException e)
37       {
38          e.printStackTrace();
39       }

 

总结:这次实验内容较多,花费了大量的时间,总的来说IO流是java中很重要的一部分,涉及面很广,还会和今后的网络编程牵扯关系,应该好好学。正值表达式的内容较难理解

posted @ 2019-11-26 18:04  cxxxxx  阅读(371)  评论(0编辑  收藏  举报