Java基础 IO流——第四部分
新博客地址:Temi
第一讲:IO流(对象的序列化)
一,对象序列化的概念:将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化)。
========被序列化对象必须实现 Serializable 接口,接口Serializable中没有方法,称之为标记接口===========
==============静态成员,和被transient 修饰的成员无法被序列化。静态成员属于类级别的,所以不能序列化这里的不能序列化的意思,是序列化信息中不包含这个静态成员域你这个测试成功,是因为你都在同一个机器(而且是同一个进程),因为你这个jvm已经把count加载进来了,所以你获取的是加载好的count,如果你是传到另一台机器或者你关掉程序重写写个程序读入test.obj,此时因为别的机器或新的进程是重新加载count的,所以count信息就是初始时的信息。====================
二,ObjectInputStream和ObjectOutputStream类的了解:
- ObjectOutputStream构造方法:public ObjectOutputStream(OutputStream out) throws IOException
- ObjectInputStream 特有方法:public final Object readObject() throws IOException, ClassNotFoundException 从 ObjectInputStream 读取对象。
- ObjectOutputStream 特有方法:public final void writeObject (Object obj) throws IOException 将指定的对象写入 ObjectOutputStream。
三,序列化操作步骤:
- 被序列化对象实现Serializable接口。
- 确定类中的serialVersionUID。=========序列化运行时使用一个称为 serialVersionUID的版本号与每个可序列化类相关联,用于验证序列化对象的发送者和接收者是否为同一对象。如果接收者加载的该对象的类的 serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final)的 long 型字段)显式声明其自己的serialVersionUID=========
- 创建对象写入流,与文件关联。 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/obj.txt"));
- 通过写入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 (输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。通过结合线程使用)
- public class PipedInputStream extends InputStream 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。
- 构造方法:public PipedInputStream() 创建尚未连接的
PipedInputStream
。在使用前必须将其连接到PipedOutputStream
。 - 构造方法:public PipedInputStream(int pipeSize) 创建一个尚未连接的
PipedInputStream
,并对管道缓冲区使用指定的管道大小。在使用前必须将其连接到PipedOutputStream
。 - 构造方法:public PipedInputStream(PipedOutputStream src,int pipeSize) throws IOException 创建一个
PipedInputStream
,使其连接到管道输出流src
,并对管道缓冲区使用指定的管道大小。写入src
的数据字节可用作此流的输入。 - 方法:public void connect(PipedOutputStream src) throws IOException 使此管道输入流连接到管道输出流
src
。如果此对象已经连接到其他某个管道输出流,则抛出IOException
。
- 构造方法:public PipedInputStream() 创建尚未连接的
- public class PipedOutputStreamextends OutputStream 可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。
- 构造方法:public PipedOutputStream() 创建尚未连接到管道输入流的管道输出流。必须在使用之前将管道输出流连接到管道输入流(既可由接收者连接,也可由发送者连接)。
- 构造方法:public PipedOutputStream(PipedInputStream snk) throws IOException 创建连接到指定管道输入流的管道输出流。写入此流的数据字节稍后将用作
snk
的输入。 - 方法:public void connect(PipedInputStream snk) throws IOException 将此管道输出流连接到接收者。如果此对象已经连接到其他某个管道输入流,则抛出
IOException
。
- public class PipedInputStream extends InputStream 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。
二,操作步骤:
- 先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法。========注:线程的异常要在内部处理=========
- 创建两个管道流,并用connect()方法将两个流连接。
- 将管道流绑定到线程。
- 创建线程并执行。
三,代码练习:
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 类的简单了解。
- 类的声明:public class RandomAccessFileextends Object implements DataOutput, DataInput, Closeable 此类的实例支持对随机访问文件的读取和写入。
- 类的说明:
- 该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过getFilePointer方法获取指针位置,来对数组的元素进行操作,同时可通过seek方法改变指针的位置。
- 可以完成读写的原理:内部封装了字节输入流和输出流。
- 构造方法:public RandomAccessFile(File file, String mode) throws FileNotFoundException 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由
File
参数指定。 - 构造方法:public RandomAccessFile(String name, String mode) throws FileNotFoundException 建从中读取和向其中写入(可选)的随机访问文件流 ====注:由构造方法可以看出该类只能操作文件。且操作文件包括模式=====
- 方法:public long length() throws IOException 按字节测量的此文件的长度。
- public void seek(long pos) throws IOException 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。===注:可以向前和向后寻找====
- public int skipBytes(int n) throws IOException 尝试跳过输入的
n
个字节以丢弃跳过的字节。返回:跳过的实际字节数。===注:只可以往前跳不可以往后跳=====
=====注:关于读写模式的说明:如果模式为只读r,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常。如果模式为读写rw,且该对象的构造函数要操作的文件不存在,会自动创建;如果存在,则不会覆盖。====
二,RandomAccessFile类的特点:
- 同一个类既有读方法也有写方法。
- 只能操作文件。
- 可以实现对文件的随机读写。
三,代码练习:
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 类的简单了解:
- ByteArrayInputStream 在构造时,需要接受数据源。。而且数据源是一个字节数组。
- ByteArrayOutputStream 在构造时,不需要指定数据源,因为在其内部已经封装的可变长度的字节数组。
- 这两个流对象操作的都是数组,没有使用系统资源,所以不需要关闭。
- 基本思想:用流的思想操作数组。
- 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流(转换流的字符编码)
一,字符概述:
- Java IO 操作中可以加入字符编码表的四个对象:
- 转换流:InuputStreamReader和OutputStreamWriter。
- 打印流:PrintStream和PrintWriter =====注:只有输出流=====
- Java IO 操作中可以加入字符编码表的四个对象:
二,编码表的由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
- 常见的编码表:ASCII:美国标准信息交换码表。用一个字节的7位表示
- IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示。====注:打头为 1======
- GB2312:中国的中文编码表(早期)两个字节表示一个字符(6-7千字符)。====注:打头的是两个高位为1的两个字节编码。===
- GBK:中国的中文编码表升级,融合了更多的中文文字字符。(两万字符左右)。====注:打头的是两个高位为1的两个字节编码。===
- Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。
-
UTF-8:最多用三个字节表示一个字符的编码表,根据字符所占内存空间不同,分别用一个、两个、三个字节来编码。
- UTF-8编码格式:一个字节:0开头。
- 两个字节:字节一 ---> 110 位数:10 ~ 6 。字节二 ---> 10 位数:5 ~ 0。
- 三个字节:字节一 ---> 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 }
第七讲:字符编码
一,编码和解码:
- 编码:字符串变成字节数组 String ---> byte[] :srt.getBytes(charsetName)
- 解码:字节数组变成字符串 byte[] ---> String :newString(byte[],charsetName)
二,编码和解码的字符集转换注意事项:
- 如果编码失败,解码就没意义了。
- 如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。
- 如果用的是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”中
二,思路:
- 描述对象
- 定义一个可操作学生对象的工具类。
- 通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
- 因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。所以可以使用TreeSet。
- 将集合的信息写入到一个文件中。
三,代码练习:
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()+"\t"); 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 }