Java基础 IO流——第四部分

 

新博客地址:Temi

第一讲:IO流(对象的序列化)

一,对象序列化的概念:将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化)。

               ========被序列化对象必须实现 Serializable 接口,接口Serializable中没有方法,称之为标记接口===========

==============静态成员,和被transient 修饰的成员无法被序列化。静态成员属于类级别的,所以不能序列化这里的不能序列化的意思,是序列化信息中不包含这个静态成员域你这个测试成功,是因为你都在同一个机器(而且是同一个进程),因为你这个jvm已经把count加载进来了,所以你获取的是加载好的count,如果你是传到另一台机器或者你关掉程序重写写个程序读入test.obj,此时因为别的机器或新的进程是重新加载count的,所以count信息就是初始时的信息。====================

二,ObjectInputStream和ObjectOutputStream类的了解:

    1. ObjectOutputStream构造方法:public ObjectOutputStream(OutputStream out)  throws IOException
    2. ObjectInputStream  特有方法:public final Object  readObject()  throws IOException,  ClassNotFoundException            从 ObjectInputStream 读取对象。
    3. ObjectOutputStream 特有方法:public final void writeObject (Object obj)  throws IOException 将指定的对象写入 ObjectOutputStream。

三,序列化操作步骤:

    1. 被序列化对象实现Serializable接口
    2. 确定类中的serialVersionUID。=========序列化运行时使用一个称为 serialVersionUID的版本号与每个可序列化类相关联,用于验证序列化对象的发送者和接收者是否为同一对象。如果接收者加载的该对象的类的 serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final)的 long 型字段)显式声明其自己的serialVersionUID=========
    3. 创建对象写入流,与文件关联。           ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/obj.txt"));
    4. 通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件。oos.writeObject(obj);

四,代码练习:

 

 1 import java.io.*;
 2 
 3 public class ObjectStreamDemo {
 4         public static void main(String[] args) {
 5             //声明并实例化被序列化对象
 6             Person per = new Person("lisi",23,01,"ss");
 7             
 8             //序列化对象
 9             try {
10                 myObjectStream_Write(per);
11             } catch (FileNotFoundException e) {
12                 System.out.println("文件没有找到"+e.toString());
13             } catch (IOException e) {
14                 System.out.println("序列化发生错误!"+e.toString());
15             }
16             
17             //接收读取的对象
18             Person per2=null;
19             
20             //反序列化对象
21             try {
22                   per2 = (Person)myObjectStream_Reader();
23             } catch (FileNotFoundException e) {
24                  System.out.println("序列还文件不存在"+e.toString());
25             } catch (ClassNotFoundException e) {
26                 System.out.println("类文件没有找到"+e.toString());
27             } catch (IOException e) {
28                 System.out.println("读取发生错误"+e.toString());
29             }
30             
31             System.out.println(per2);
32         }
33         
34         
35         //自定义序列化 方法,将对象序列化到硬盘上
36         public static void myObjectStream_Write(Object obj) throws FileNotFoundException, IOException{
37             
38             //声明序列化输出流对像。并于文件相关联
39             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/obj.txt"));
40             
41             //将对象序列化到硬盘上
42             oos.writeObject(obj);
43             
44             //关闭流
45             oos.close();
46         }
47         
48         
49         //自定义读取序列化对象方法
50         public static Object myObjectStream_Reader() throws FileNotFoundException, IOException, ClassNotFoundException{
51             
52             //声明序列化输入流,并于文件关联
53             ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/obj.txt"));
54             
55             
56             //读入被序列化的对象
57             Object object = ois.readObject();
58             
59             //关闭流
60             ois.close();
61             
62             return object;
63             
64         }
65 }

 

Person 类:

 1 import java.io.Serializable;
 2 
 3 
 4 //定义Person类实现Serializable接口,表明可以被序列化
 5 public class Person implements Serializable{
 6        
 7     //定义serialVersionUID 表明版本号
 8     private static final long serialVersionUID = 1L;
 9     
10     //定义类成员
11     private String name;
12     private int age;
13     
14     //transient修饰符修饰的成员不可以被序列化
15     transient int id;
16     
17     //静态成员不可以被序列化
18     static String country="aa";
19     
20     
21     //定义构造方法
22     public Person(String name,int age,int id,String country){
23         this.name=name;
24         this.age=age;
25         this.id=id;
26         this.country=country;
27     }
28     
29     @Override
30     public String toString(){
31         return "name:"+name+"---"+"age:"+age+"----"+"id:"+id+"----"+"country"+country;
32     }
33 
34 }

第二讲:IO流(管道流)

一,管道流:PipedInputStream 和 PipedOutputStream  (输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。通过结合线程使用)

    1. public class PipedInputStream  extends InputStream      管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。
      1. 构造方法:public PipedInputStream()   创建尚未连接的 PipedInputStream。在使用前必须将其连接到 PipedOutputStream
      2. 构造方法:public PipedInputStream(int pipeSize)  创建一个尚未连接的 PipedInputStream,并对管道缓冲区使用指定的管道大小。在使用前必须将其连接到 PipedOutputStream
      3. 构造方法:public PipedInputStream(PipedOutputStream src,int pipeSize) throws IOException  创建一个 PipedInputStream,使其连接到管道输出流 src,并对管道缓冲区使用指定的管道大小。写入 src 的数据字节可用作此流的输入。
      4. 方法:public void connect(PipedOutputStream src) throws IOException    使此管道输入流连接到管道输出流 src。如果此对象已经连接到其他某个管道输出流,则抛出 IOException
    2. public class PipedOutputStreamextends OutputStream     可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。
      1. 构造方法:public PipedOutputStream()       创建尚未连接到管道输入流的管道输出流。必须在使用之前将管道输出流连接到管道输入流(既可由接收者连接,也可由发送者连接)。
      2. 构造方法:public PipedOutputStream(PipedInputStream snk) throws IOException    创建连接到指定管道输入流的管道输出流。写入此流的数据字节稍后将用作 snk 的输入。
      3. 方法:public void connect(PipedInputStream snk)  throws IOException    将此管道输出流连接到接收者。如果此对象已经连接到其他某个管道输入流,则抛出 IOException

二,操作步骤:

    1. 先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法。========注:线程的异常要在内部处理=========
    2. 创建两个管道流,并用connect()方法将两个流连接
    3. 将管道流绑定到线程。
    4. 创建线程并执行。

三,代码练习:

 

  1 import java.io.*;
  2 
  3 //定义一个类,实现启动一个线程,次线程包括一个读的管道刘
  4 class Read implements Runnable{
  5     private PipedInputStream in;
  6     public Read(PipedInputStream in){
  7         this.in = in;
  8     }
  9     
 10     @Override
 11     
 12     //覆写方法
 13     public void run(){
 14         
 15            //接受输入数据
 16            byte buff[] = new byte[1024];
 17            
 18            
 19            //记录数据长度
 20            int len=0;
 21            
 22            
 23            //循环接受数据
 24            while(true){
 25                try{
 26                    
 27                    //尝试读取数据
 28                    len = in.read(buff);
 29                    
 30                    //判断是否结束
 31                    if("over".equals(new String(buff,0,len-2)))
 32                        break;
 33                    
 34                    //输出用户输入的内容
 35                    System.out.println("管道读取内容为:"+new String(buff,0,len)+len);
 36                }catch(IOException e){
 37                    System.out.println("读取异常"+e.toString());
 38                }
 39            }
 40            
 41            //给出运行完毕提示
 42            System.out.println("运行完毕");
 43     }
 44 }
 45 
 46 //定义一个类,实现启动一个线程,此线程包括一个写的管道流
 47 class Write implements Runnable{
 48     
 49     //声明管道流对象
 50     private PipedOutputStream out;
 51     
 52     //构造方法
 53     public Write(PipedOutputStream out){
 54         this.out = out;
 55     }
 56     
 57     @Override
 58     
 59     //覆写方法
 60     public void run(){
 61         
 62            //接受管道数据
 63            byte buff[] = new byte[1024];
 64            
 65            int len=0;
 66            
 67            
 68            //循环读取
 69            while(true){
 70                try{
 71                    len=System.in.read(buff);
 72                    
 73                    
 74                    //输出数据
 75                    out.write(buff, 0, len);
 76                    
 77                    //判断是否结束
 78                    if("over".equals(new String (buff,0,len-2)))
 79                        break;
 80                }catch(IOException e){
 81                    System.out.println("管道读取流发生异常"+e.toString());
 82                }
 83            }
 84            
 85            //给出结束提示
 86            System.out.println("运行完毕");
 87            
 88     }
 89 }
 90 public class PipedStreamDemo {
 91              public static void main(String[] args) {
 92                  
 93                         //创建 管道流对象作为参数
 94                         PipedInputStream pis = new PipedInputStream();
 95                         PipedOutputStream pos = null;
 96                         
 97                         //将管道流相连接
 98                         try {
 99                             pos = new PipedOutputStream(pis);
100                         } catch (IOException e) {
101                             // TODO Auto-generated catch block
102                             e.printStackTrace();
103                         }
104                         
105                         //创建线程
106                         Thread t1 = new Thread(new Read(pis));
107                         Thread t2 = new Thread(new Write(pos));
108                         
109                         
110                         //启动线程
111                         t1.start();
112                         t2.start();
113             }
114 }

 

第三讲:IO流(RandomAccessFile)

一,RandomAccessFile 类的简单了解。

      1. 类的声明:public class RandomAccessFileextends Object  implements DataOutput, DataInput, Closeable  此类的实例支持对随机访问文件的读取和写入。
      2. 类的说明:
        1. 该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过getFilePointer方法获取指针位置,来对数组的元素进行操作,同时可通过seek方法改变指针的位置。
        2. 可以完成读写的原理:内部封装了字节输入流和输出流。
      3. 构造方法:public RandomAccessFile(File file, String mode) throws FileNotFoundException    创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
      4. 构造方法:public RandomAccessFile(String name, String mode) throws FileNotFoundException   建从中读取和向其中写入(可选)的随机访问文件流 ====注:由构造方法可以看出该类只能操作文件。且操作文件包括模式=====
      5. 方法:public long length() throws IOException    按字节测量的此文件的长度。
      6. public void seek(long pos) throws IOException    设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。===注:可以向前和向后寻找====
      7. public int skipBytes(int n) throws IOException    尝试跳过输入的 n 个字节以丢弃跳过的字节。返回:跳过的实际字节数。===注:只可以往前跳不可以往后跳=====

=====注:关于读写模式的说明:如果模式为只读r,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常。如果模式为读写rw,且该对象的构造函数要操作的文件不存在,会自动创建;如果存在,则不会覆盖====

二,RandomAccessFile类的特点:

      1. 同一个类既有读方法也有写方法。
      2. 只能操作文件。
      3. 可以实现对文件的随机读写。

三,代码练习:

 1 package com.examp.ch18;
 2 //需求:使用RandomAccessFileDemo进行读写操作
 3 
 4 import java.io.*;
 5 public class RandomAccessFileDemo {
 6     
 7     public static void main(String[] args)throws IOException {
 8         
 9         //创建文件对象
10         File file =new File("E:/test.txt");
11 
12         //写数据
13         writeFile(file);
14 
15         //读数据
16         readFile(file);
17 
18     }
19 
20     //读取指定文件中的数据
21     public static void readFile(File file)throws IOException{
22         
23         
24         //创建随机读写对象,指定文件打开方式为只读
25         RandomAccessFile raf=new RandomAccessFile(file,"r");
26         
27         //设置指针位置
28         raf.seek(8);
29 
30         //读取四个字节存入
31         byte[] by=new byte[4];
32         
33         
34         //读数据
35         raf.read(by);
36         
37         
38         //将存入数据的字节数组转换为字符串
39         String name=new String(by);
40         
41         
42         //读取年龄
43         int age=raf.readInt();
44         
45         System.out.println("name="+name+"age="+age);
46 
47         //关闭流对象
48         raf.close();
49     }
50 
51     //创建方法将数据写入指定文件中
52     public static void writeFile(File file)throws IOException{
53         
54         //创建对象,文件打开方式为读写
55         RandomAccessFile raf=new RandomAccessFile(file,"rw");
56         
57         //写入姓名
58         raf.write("张三".getBytes());
59         
60         
61         //写入年龄,这里调用了写一个int方法
62         raf.writeInt(23);
63 
64         raf.write("李四".getBytes());
65         raf.writeInt(100);
66       
67         //改变指针位置,改变第一个对象的值
68         raf.seek(8*0);
69         raf.write("小三".getBytes());
70         raf.writeInt(3);
71 
72         
73         //改变指针位置
74         raf.skipBytes(8*2);
75         raf.write("王五".getBytes());
76         raf.writeInt(5);
77 
78         //关闭流
79         raf.close();    
80     }
81 }

 

第四讲:IO流(操作基本数据类型的流对象DataStream)

一,ByteArrayInputStream和ByteArrayOutputStream 类的简单了解:

      1. ByteArrayInputStream 在构造时,需要接受数据源。。而且数据源是一个字节数组。
      2. ByteArrayOutputStream 在构造时,不需要指定数据源,因为在其内部已经封装的可变长度的字节数组。
      3. 这两个流对象操作的都是数组,没有使用系统资源,所以不需要关闭。
      4. 基本思想:用流的思想操作数组。
      5. ByteArrayOutputStream  方法:public void writeTo(OutputStream out)  throws IOException         将此 byte 数组输出流的全部内容写入到指定的输出流参数中。==注:此方法抛出异常。===

二,对应的字符操作类:CharArrayReader和CharArrayWriter

        对应的字符串操作类: StringReader和StringWriter

三,代码练习:

 1 import java.io.*;
 2 
 3 public class ByteArrayInputStreamDemo {
 4            public static void main(String[] args) {
 5                
 6                //定义字节操作输入流,源为一个字符串的字节数组形式
 7                ByteArrayInputStream bais=new ByteArrayInputStream("abcdef".getBytes());
 8                
 9                //定义字节操作输出流
10                ByteArrayOutputStream baos=new ByteArrayOutputStream();
11                
12                //接受读入的内容
13                int by=0;
14                
15                //循环读取写入内容
16                while((by = bais.read())!=-1){
17                    baos.write(by);
18                }
19                
20                //输出字节操作流写入的内容
21                System.out.println(baos.toString());
22         }
23 }

第五讲:IO流(ByteArrayStream)

 

 

第六讲:IO流(转换流的字符编码)

一,字符概述:

    1. Java IO 操作中可以加入字符编码表的四个对象:
      1. 转换流:InuputStreamReader和OutputStreamWriter
      2. 打印流:PrintStream和PrintWriter    =====注:只有输出流=====

二,编码表的由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

  1. 常见的编码表:ASCII:美国标准信息交换码表。用一个字节的7位表示
  2. IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示。====注:打头为 1======
  3. GB2312:中国的中文编码表(早期)两个字节表示一个字符(6-7千字符)。====注:打头的是两个高位为1的两个字节编码。===
  4. GBK:中国的中文编码表升级,融合了更多的中文文字字符。(两万字符左右)。====注:打头的是两个高位为1的两个字节编码。===
  5. Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
  6. UTF-8:最多用三个字节表示一个字符的编码表,根据字符所占内存空间不同,分别用一个、两个、三个字节来编码。

    1. UTF-8编码格式:一个字节:0开头
    2.  两个字节:字节一  ---> 110    位数:10 ~ 6 。字节二  ---> 10     位数:5 ~ 0
    3. 三个字节:字节一  ---> 110    位数:15 ~ 12 字节二  ---> 10     位数:11 ~ 6 字节三 ---> 10     位数:5 ~ 0

三,代码练习:

  1 import java.io.*;
  2 
  3 
  4 public class EncodingStream {
  5              public static void main(String[] args) {
  6                  
  7                  //分别创建两个文件对象,用来存储两种编码格式的数据
  8                  File file_GBK = new File("E:/gbk.txt");
  9                  File file_UTF = new File("E:/utf.txt");
 10                  
 11                  //分别按照两种编码格式写入数据
 12                  try {
 13                     writeText_GBK(file_GBK);
 14                     writeText_UTF(file_UTF);
 15                 } catch (IOException e) {
 16                     System.out.println("写入文件发生异常"+e.toString());
 17                 }
 18                  
 19                  
 20                  //按照两种编码格式分别读取两个文件
 21                  try {
 22                      
 23                      //正常
 24                      System.out.println("正常:");
 25                     readText_GBK(file_GBK);
 26                     //乱码
 27                     System.out.println("乱码");
 28                     readText_GBK(file_UTF);
 29                     //正常
 30                     System.out.println("正常:");
 31                     readText_UTF(file_UTF);
 32                     //乱码
 33                     System.out.println("乱码");
 34                     readText_UTF(file_GBK);
 35                 } catch (IOException e) {
 36                     System.out.println("读入文件发生错误"+e.toString());
 37                 }
 38                  
 39             }
 40              
 41              
 42              //定义方法将数据按GBK编码写入文件
 43              public static void writeText_GBK(File file) throws IOException{
 44                  
 45                     //创建输出字符流,使用指定的文件,以及编码
 46                     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file),"gbk");
 47                     
 48                     
 49                     //写入内容
 50                     osw.write("黑马训练营");
 51                     
 52                     //刷新流
 53                     osw.flush();
 54                     //关闭流
 55                     osw.close();
 56              }
 57              
 58              
 59              //定义方法,将数据按照GBK编码从文件中读入
 60              public static void readText_GBK(File file) throws IOException{
 61                  
 62                     //创建文件读取字符流,使用指定的编码,以及文件
 63                     InputStreamReader isr = new InputStreamReader(new FileInputStream(file),"gbk");
 64                     
 65                     //接受读入的字符
 66                     char ch[] = new char[1024];
 67                     
 68                     //标记读入的字符数
 69                     int  len=0;
 70                     
 71                     //循环读取打印
 72                     while((len=isr.read(ch))!=-1){
 73                         System.out.println(new String(ch,0,len));
 74                     }
 75                     //关闭流操作
 76                     isr.close();
 77              }
 78              
 79              
 80              //定义方法,将数据按照UTF-8编码写入指定的文件
 81              public static void writeText_UTF(File file) throws IOException{
 82                  
 83                     //创建输出字符流,使用指定的文件,以及编码
 84                     OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file),"UTF-8");
 85                     
 86                     //写出数据
 87                     osw.write("黑马训练营");
 88                     
 89                     osw.flush();
 90                     
 91                     osw.close();
 92              }
 93              
 94              
 95              //定义方法,将数据按照UTF-8编码从指定文件读入
 96              public static void readText_UTF(File file)throws IOException{
 97                     //创建文件读取字符流,使用指定的编码,以及文件
 98                     InputStreamReader isr = new InputStreamReader(new FileInputStream(file),"UTF-8");
 99                     
100                     //定义数组接受字符
101                     char ch[] = new char[1024];
102                     
103                     //标记
104                     int len=0;
105                     
106                     //循环读取
107                     while((len=isr.read(ch))!=-1){
108                         System.out.println(new String(ch,0,len));
109                     }
110                     
111                     isr.close();
112              }
113 }

第七讲:字符编码

一,编码和解码

    1. 编码:字符串变成字节数组       String  --->  byte[]  :srt.getBytes(charsetName)
    2. 解码:字节数组变成字符串         byte[]   --->  String :newString(byte[],charsetName)

二,编码和解码的字符集转换注意事项

      1. 如果编码失败,解码就没意义了。
      2. 如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。
      3. 如果用的是GBK编码,UTF-8解码,此时通过再次编码后解码的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。

 

三,代码练习:

 1 import java.util.Arrays;
 2 
 3 public class EncodingDemo {
 4             public static void main(String args[]) throws Exception{
 5                 
 6                 //创建一个字符串
 7                 String s="您好";
 8                 //获得字符串的GBK 码表
 9                 byte[] b1 = s.getBytes("gbk");
10                 //输出码表
11                 System.out.println(Arrays.toString(b1));
12                 //重新编码
13                 String s1 = new String(b1,"gbk");
14                 
15                 System.out.println("s1="+s1);
16                 
17                 //获取字符串的ISO8859-1码表
18                 byte[] b2 = s1.getBytes("ISO8859-1");
19                 //输出码表
20                 System.out.println(Arrays.toString(b2));
21                 //重新编码
22                 String s2 = new String (b2,"gbk");
23                 
24                 System.out.println(s2);
25             }
26 }

第八讲:字符编码-联通

一,对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,所以在文本文件中,如果单独写“联通”或者和满足UTF-8编码格式的字符一起保存时,记事本就会用UTF-8来进行解码动作,这样显示的就会是乱码。

    解决办法:在联通前面加上任意中文字符。

二,代码练习:

 

 1 import java.io.UnsupportedEncodingException;
 2 
 3 public class LianTongDemo {
 4             public static void main(String[] args) throws UnsupportedEncodingException {
 5                    String s = "联通";
 6                    
 7                    byte[] bytes = s.getBytes("gbk");
 8                    
 9                    for(byte b : bytes){
10                        System.out.println(Integer.toBinaryString(b&255));
11                    }
12             }
13 }

 

第九讲:练习

一,需求分析:

                  有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩输入的格式:如:张三,30,40,60计算出总成绩,并把学生的信息和计算出的总分数由高低顺序存放在磁盘文件“stuinfo.txt”中

二,思路:

    1. 描述对象
    2. 定义一个可操作学生对象的工具类。 
    3. 通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
    4. 因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。所以可以使用TreeSet。
    5. 将集合的信息写入到一个文件中。

三,代码练习:

  1 import java.io.*;
  2 import java.util.*;
  3 
  4 
  5 //学生类实现Comparable接口
  6 class Student implements Comparable<Student>{
  7     private String name;
  8     private int sx,yy,yw,sum;
  9     Student(String name,int sx,int yw,int yy){
 10         this.name=name;
 11         this.sx=sx;
 12         this.yw=yw;
 13         this.yy=yy;
 14         sum=sx+yw+yw;
 15     }
 16 
 17     //获取总成绩
 18     public int getSum(){
 19         return sum;
 20     }
 21 
 22     //获取姓名
 23     public String getName()
 24     {
 25         return name;
 26     }
 27 
 28     //复写compareTo方法
 29     public int compareTo(Student s)    {
 30         
 31         int num=new Integer(this.sum).compareTo(new Integer(s.sum));
 32         if(num==0)
 33             return this.name.compareTo(s.name);
 34         return num;
 35     }
 36     
 37     //复写hashCode
 38     public int hashCode(){
 39         
 40         return name.hashCode()+sum*33;
 41     }
 42 
 43     //复写equals
 44     public boolean equals(Object obj){
 45         
 46         if(!(obj instanceof Student))
 47             throw new ClassCastException("类型不匹配");
 48         Student s=(Student)obj;
 49         return this.name.equals(s.name)&&this.sum==s.sum;
 50     }
 51 
 52     
 53     //复写toString
 54     public String toString(){
 55         return "Student["+name+","+sx+","+yw+","+yw+"]";
 56     }
 57 }
 58 
 59 //学生工具类
 60 class StudentTools{
 61     //从键盘读取学生信息方法,以学生自身排序方式存入集合中
 62     public static Set<Student> getStudentInfo_1()throws IOException
 63     {
 64          return getStudentInfo_2(null);
 65     }
 66 
 67     //从键盘读取学生信息方法,以比较器排序方式存入集合中
 68     public static Set<Student> getStudentInfo_2(Comparator<Student> cmp)throws IOException
 69     {
 70         //键盘录入
 71         BufferedReader bis=
 72             new BufferedReader(new InputStreamReader(System.in));
 73         String info=null;
 74 
 75         //定义一个集合,用来存储学生对象
 76         Set<Student> set=null;//---------
 77         if(cmp==null)
 78             set=new TreeSet<Student>();
 79         else
 80             set=new TreeSet<Student>(cmp);
 81 
 82         //读取数据
 83         while((info=bis.readLine())!=null)
 84         {
 85 
 86             if("over".equals(info)) 
 87                 break;
 88 
 89             String[] in=info.split(",");
 90             //将学生对象存入集合中
 91             set.add(new Student(in[0],Integer.parseInt(in[1]),
 92                                     Integer.parseInt(in[2]),
 93                                     Integer.parseInt(in[3])));
 94         }
 95         bis.close();//关流
 96 
 97         return set;
 98     }
 99 
100     //把学生信息按照指定属性写入指定文件中
101     public static void writeToFile(Set<Student> set,File file)throws IOException
102     {
103         //关联文件
104         BufferedWriter bw=new BufferedWriter(new FileWriter(file));
105 
106         //遍历
107         for (Student stu : set)
108         {
109             //将学生信息写入指定文件中
110             bw.write(stu.toString()+"	");
111             bw.write(stu.getSum()+"");
112             bw.newLine(); 
113             bw.flush();
114         
115         }
116         
117         bw.close();//关流
118     }
119 }
120 
121 
122 public class  StudentInfoTest
123 {
124     public static void main(String[] args) 
125     {
126         //定义一个翻转自身比较性的比较器
127         Comparator<Student> cmp=Collections.reverseOrder();
128         try
129         {
130             //指定文件
131             File file =new File("stdinfo.txt");
132     
133             //调用学生工具类的获取信息方法,将信息存入集合中
134             Set<Student> set=StudentTools.getStudentInfo_2(cmp);
135 
136 
137             //将学生信息写入指定文件中
138             StudentTools.writeToFile(set,file);
139         }
140         catch (IOException e)
141         {
142             throw new RuntimeException("学生信息获取写入失败");
143         }    
144     }
145 }
 
原文地址:https://www.cnblogs.com/xiaochongbojue/p/4052580.html