黑马程序员--Java基础之IO流(2)

黑马程序员--Java基础之IO流(2)

------------------------------------ android培训java培训、期待与您交流! ----------------------------------

10、IO流--Properties简述

        properties 是hashtable的子类,它具备Map集合的特点,而且它里面存储的键值对都是字符串。它是集合和IO技术相结合的集合容器。

        该对象的特点:可以用于键值对形式的配置文件。那么在加载数据时,需要数据有固定格式:键=值。

Properties设置和获取元素:

Object setProperty(String key,Stringvalue);//设置键值对
StringgetProperty(String key);//获取键为key的属性
Properties的load方法,load方法是1.6版本之后才有的,将流中的数据加载到Properties集合中:p.load(字节或者字符流);

Properties其他方法:

void list(PrintStream out);//将属性列表输出到指定的输出流,比如:void list(System.out);//输出到控制台
setProperty(””,””)方法改变的是内存的信息,并没有将配置文件的信息修改,要想也将文件中的配置信息也修改,需要使用方法store(OutputStream out, String cements);//第二个参数是注释,加载到文件的最上面,带#号,配置信息中带#号的默认是注释,默认不会加载。先声明一个输出流与该配置文件相关联,然后用store方法将参数流写进去。

Properties练习:记录应用程序运行次数,如果使用次数已到,那么给出注册提示。代码示例:

/*
       Properties练习
       1、用于记录应用程序运行次数
       如果使用次数已到,那么给出注册提示
      
       首先要获取配置文件中的计数信息
       然后判断,到次数就提示需要注册
       */
       //注意第一次编写如果有错误,一定要把上一次运行时产生的file对象删除,以免影响修改后代码的结果。!!
       public static void countTime()throwsIOException
       {
              Properties prop = newProperties();
              File file = newFile("count.properties");
              if(!file.exists())//如果该文件不存在就创建一个,存在则不用创建
                     file.createNewFile();
             
              FileInputStream fis = newFileInputStream(file);
              prop.load(fis);
              String value =prop.getProperty("time");//获取键值为time的信息
              int c = 0;//定义一个记数器
              if(value != null)//如果值不为空,则取出这个值并加1,
              {    
                     c =Integer.parseInt(value);
                     if(c>=5)//到达上限次数,程序停止运行,且提示注册信息
                     {
                            System.out.println("免费体验次数已到,请注册后方能使用");
                            return ;
                     }
              }
              c++;//如果取出的值为空,则为零加1,
              prop.setProperty("time",c+"");//将自增后的值存入原配置文件中
              prop.store(newFileOutputStream(file),"");
              System.out.println("正常运行");
       }

11、其他流

*打印流:PrintStream和PrintWriter

*合并流(序列流): SequenceInputStream

*对象的序列化:ObjectOutputStream/ObjectInputStream

ObjectOutputStream,可以将对象由堆内存存储到文件中,实现了对象由内存搬运到硬盘中,被称为对象的持久化存储。

由ObjectOutputStream存储,必须要由ObjectInputStream读取,二者成对出现。

要被持久化存储的对象必须实现Serializable接口,才能被序列化。Serializable接口中没有方法,但是会给该类生成的对象产生一个uid,序列号。序列号是由该对象的成员决定的,所以当成员发生变化时,如变成私有化,再生成的对象,其序列化也会发生变化,当你按之前的序列号读取时会发生notfound异常。

*管道流PipedInputStream PipedOutputStream,写入流(输出流)写入到管道中,输入流直接从管道中将数据读取,不需要中间的文件中转。

* RandomAccessFile随机访问文件,自身具备读写的方法,自身能够读写文件。

*操作基本数据类型的流对象DataInputStream和DataOutputStream。

*用于操作字节数组的流对象:

ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组。

ByteArrayOutputStream:在构造的时候,不用定义数据目的地,因为该对象中已经内部封装了可变长度的字节数组。这就是数据的目的地。

因为这两个流对象操作的都是数组,并没有使用系统底层资源,所以不用进行close关闭。即使关闭了,它仍然可以被调用,因此关闭时无效的。

*操作字符数组的流,CharArrayReader和CharArrayWrite。

*操作字符串的流,StringReader和StringWriter。

12、码表简述

常见的编码表:ASCII、ISO8859-1、GB2312、GBK、Unicode、UTF-8。

中文编码为GB2312、GBK。GBK是GB2312的升级版。

国际通用UTF-8。

使用什么编码写入,就用什么编码读出,否则会乱码。

不同的编码表,其编码特点不一样,比如GBK两个字节代码一个字符,且每个字节的第一个位为1,所以都为负数。而utf-8码表有自己的标识头:0开始表示读一个字节;110开始表示读两个字节:110...,10...,;1110表示度三个字节才查表:1110..,10..,10..

有趣现象--联通

当使用记事本存储时,开头为“联通”二字存入时,保存后再打开发现乱码。

原因是,联通二字很奇怪,使用GBK编码时,其字节数字正好符合了utf-8的编码的标识头!记事本会自动将该文件按照utf-8编码保存,所以导致解码错误。

解决办法:只需要文件开头时变成其他汉字,不然“联通”二字在前面就行了。

13、练习

需求:

    有五个学生,没个完学生有3门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩),

输入的格式:如:张三,30,40,60 并计算出总成绩。

最后把学生的信息和计算出的总分数按高低顺序存放在磁盘文件“stud.txt”中。

思路:

   *描述学生对象。

   *定义一个可操作学生对象的工具类。

步骤:

   1、通过键盘录入一行数据,并将该行中的信息取出封装成学生对象。

   2、因为学生有很多,那么就需要存储,使用到集合,又因为要对学生的总分排序,所以可以使用TreeSet集合。

   3、将集合的信息写入到一个文件中。

代码示例:

class Test21_9
{
       public static void main(String[]args)throws IOException
       {
              Set<Student> s =StudentTool.getStu();
              StudentTool.storeStu(s);
       }
}
//一个学生类,需要继承Comparable接口,因为要存储到TreeSet集合中,要有自己的自然排序
class Studentimplements Comparable<Student>
{
       private String name;
       private double cn;//这里如果使用int型的会比较方便些
       private double ma;
       private double en;
       private double sum;
      
       Student(String name,double cn,doublema,double en)
       {
              this.name = name;
              this.cn = cn;
              this.ma = ma;
              this.en = en;
              sum = cn+ma+en;
       }
      
       public int compareTo(Student s)
       {
              int num = newDouble(this.sum).compareTo(new Double(s.sum));
              if(num == 0)
              {
                     returnthis.name.compareTo(s.name);
              }
             
              return num;
       }
      
       //由于该对象存入的是Set的子集集合,所以为了保证集合元素的唯一性,需要重写hashCode和equals方法。
       //先比较hashCode方法的值,如果相等还会比较equals方法的值
       public int hashCode()
       {
              return name.hashCode() + ((newDouble(sum)).hashCode()*24);
       }
      
       public boolean equals(Object obj)
       {
              if(!(obj instanceof Student))
                     throw new  ClassCastException("不是Student的对象");
              Student s = (Student)obj;
              return this.name.equals(s.name)&&(newDouble(this.cn)).equals(s.cn)&&(newDouble(this.ma)).equals(s.ma)&&(new Double(this.en)).equals(s.en);
       }
      
       public String toString()
       {
              returnthis.name+","+this.cn+","+this.ma+this.en+"            "+this.sum;
       }
      
       public double getSum()
       {
              return this.sum;
       }
       public String getName()
       {
              return this.name;
       }
}
//定义一个操作学生对象的工具类
class StudentTool
{
       public static Set<Student>getStu()throws IOException
       {    
              Set<Student> set = newTreeSet<Student>();
              BufferedReader bfr = new BufferedReader(newInputStreamReader(System.in));
              String line = null;
              while((line =bfr.readLine())!=null)
              {     if(line.equals("over"))
                     {
                            break;
                     }    
                     String[] arr =line.split(",");
                     Student s = newStudent(arr[0],Double.parseDouble(arr[1]),Double.parseDouble(arr[2]),Double.parseDouble(arr[3]));
                     set.add(s);
              }
              bfr.close();
              return set;
       }
      
       public static voidstoreStu(Set<Student> set)throws IOException
       {
              BufferedWriter bfw = newBufferedWriter(new FileWriter("Stu.txt"));
              for(Student stu:set)
              {
                     bfw.write(stu.toString()+"\t");
                     //bfw.write(stu.getSum()+"\t");
                     bfw.newLine();
                     bfw.flush();
              }
              bfw.close();
       }
      
}

三、一些注意事项

1、流使用完毕一定要关闭资源。

2、IO流的异常处理try{}catch(){}finally{},关闭资源要放在finally中。

3、记住“”中写目录时,\分隔符要注意转义了,需要写两个:\\。

4、OutputStream中write(byte);方法读的是字节,注意是字节。有时读取文字时是字符型的,需要转换成字节型的,如“abcf”.getBytes();

5、读取时有可能读取的第一个字节(八位)是-1的补码,当自动提升为int型时,还是-1,造成假的结束判断条件,所以需要将提升为int型的字节&255,只取提升之前的后八位。

6、字节流中int available()方法,返回的是操作文件中的字符数,包括回车符\r\n也计算在内,因此可以定义一个刚刚好的缓冲区:

 int num = fis.available();byte[] buf = newbyte(num);

但是,很有可能在读取一个很大的文件时,容易超出容量,造成内存溢出。

所以还是建议定义的缓冲数组,大小设定为1024,这是比较折中的方法,好使。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值