admin 管理员组

文章数量: 887021

(十二)Core Java IO流(Properties,序列化,管道流,字符编码)



 目录 :             41 ). IO流(创建java文件列表)
42 ). IO流(Properties简述)

43 ). IO流(Properties存取)

44 ). IO流(Properties存取配置文件)

45 ). IO流(Properties练习)

46 ). IO流(PrintWriter)

47 ). IO流(合并流)

48 ).IO流(切割文件)

49 ).IO流(对象的序列化)

50 ). IO流(管道流)

51 ). IO流( RandomAccessFile)

52 ). IO流( 操作基本数据类型的流对象DataStream)

53 ). IO流(ByteArrayStream)

54 ). IO流(转换流的字符编码)

55 ).字符编码

56 ).字符编码-联通

57 ).练习
   

     四十一 .   IO流(创建java文件列表)
1 ) .   本文讲述 如何将 指定目录中的文件递归到集合,然后从集合通过字符流写入到指定目标地址文件
2 ) . Demo:

/*           本章讲述 :           需求 :  将一个指定目录下的java文件的绝对路径,存储到一个文本文件中         也就是建立一个java文件列表清单                 步骤:         1.对指定的目录进行递归         2.获取递归过程所有的java文件的路径         3.将这些路径存储到集合中         4,将集合中的数据写入到一个文件中           */         import java.io.*;      import java.util.*;    class javaFileList   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                              //将指定目录下的文件放入指定集合中                       public static void fileToList(File file,List<File> list)                       {                                             //获取遍历文件对象的类                              File[] file1 = file.listFiles();                              //遍历文件对象                              for(File fi : file1)                              {                                    //判断是否是目录                                    if(fi.isDirectory())                                           fileToList(fi,list);  //是目录继续递归遍历                                                                       else                                    {      if(fi.getName().endsWith(".java"));  //是文件再判断是否是.java文件                                                      list.add(fi);                    //是.java文件则添加入集合                                                                              }                                                                 }                                                                                                              }                                             //用来将集合中的文件绝对路径放入指定地址文件的方法                       public static void getFileList(List<File> list,String name) throws IOException                       {                              //因为文件内是字符串涉及数据因此用字符流                              BufferedWriter bw= null;                                                           try                              {                                                                       bw=new BufferedWriter(new FileWriter(name));                                    //将list集合中数据遍历出                                    for(File fi : list)                                    {                                              String path = fi.getAbsolutePath();  //获取文件绝对路径                                           bw.write(path);  //写入目标地文件内                                           bw.newLine();    //换行                                           bw.flush();      //刷新                                                                                }                                                                 }                              catch(IOException o)                              {                                    throw o;                              }                              finally                              {                                    try                                    {                                           if(bw!=null)                                                  bw.close();                                                                              }                                    catch(IOException o)                                    {                                           throw  o;                                    }                                                                 }                                                                                 }                                        //主方法                 public static void main(String args[]) throws IOException                        {                                                         //初始化文件对象的目标地                            File fi1 = new File("S:\\develop\\JavaText");                            //初始化一个存文件的集合                            List<File> li =new ArrayList<File>();                                                         //调用文件存储到集合的方法                              fileToList(fi1,li);                                                           File fi2= new File("S:\\develop\\JavaText\\myJavaList.txt");  //指定一个目标存放地文件                                                           getFileList(li,fi2.toString());  //将list集合与目标存放地一并传入                                                           //打印集合大小                              sop(li.size());                                                                                             }                        }                   


 
小结 :  

             1.  数据存储在内存时临时存储,数据存储在硬盘式数据的持久化存储
        
           2.  数组有长度,集合有大小

        

       四十 二.  IO流(Properties简述)

1 ) . Properties
1.1 配置文件中的数据大多是以键值对的方式存在的,因此Properties是HashTable 的子类

1.2  特点 : Properties不仅可以操作键值对(设计Map体系),还可操作硬盘上(涉及IO流)的键值对

2 ) . 案例解说 : 当我们对一个软件的相关用户信息进行更改时,是在内存中更改的,而正常情况退出后,更改就失效了, 而如何让下次打开软件还是自己上次配置的,就用到了软件配置信息文件,我们通过更改配置信息文件中的数据而完成数据持久化,再启动软件之前先访问这个配置文件信息
2.1 通俗讲 : 想要当软件的配置每次打开都是上次配置的,那就需要将配置文件信息数据持久化,每次打开软件都会访问一次配置文件

3 ). Demo:

/*           本章讲述 :           Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串                 Properties是集合中和IO技术相结合的集合容器                 该对象的特点是:可以用于键值对形式的配置文件                             */                    



 
小结 :  

             1.  当我们操作硬盘上的键值对文件时,便要想到Properties类
        
 


     四十  三.  . IO流(Properties存取)
1 ) .  Properties 存   setProperty()  设置一对 :   getProerty()  取一个 ,    stringPropertyNames() 取一堆

2 ) . Demo:

/*           本章讲述 :    Properties类  :   是集合中与IO技术相结合的容器                setProperty(): 用来设置Properties类中的键值对        getProerty() :  用来通过键获取properties类中的值                stringPropertyNames() :  用来获取properties类中所有的键,返回值是set类型     */         import java.io.*;      import java.util.*;    class PropertiesDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                                 public static void getAndSet()                     {                                                         Properties pro =new Properties();   //初始化资源集合类                                                         pro.setProperty("summer","hot");    //设置资源键值对                             pro.setProperty("winter","cold");                                                         String value =       pro.getProperty("summer");  //通过键获取值                                                        //sop("sumer:"+value);    //输出值                                                                                                                 Set<String> keys  = pro.stringPropertyNames();  //获取资源集合类中所有键                                                        for(String key : keys)  //迭代键                            {                                                                    sop(key+"::"+pro.getProperty(key));  //输出所有键值                            }                                                                                             }                                                                 //主方法                 public static void main(String args[]) throws IOException                        {                                                          getAndSet();                                             }          }                   
 
 
    四十   四.  IO流(Properties存取配置文件)
1 ) .  Properties存取配置文件  :  用到了资源类中的 load () 加载  和 store()存储方法

2 ) . Demo:

/*           本章讲述 :       演示 :如何将流中的数据存储到集合中   案例 : 将info.txt文件中的键值对信息存储到集合中进行操作   步骤 :     [1] 用一个流和info.txt文件关联   [2] 读取一行数据,将该行数据用"="进行切割   [3] 等号左边作为键,右边作为值,存入到Properties集合中即可     方法:     properties类中的load() :     用来将字符/字节流指定文件中数据加载到资源类中     properties类中的store() :     用来将资源类中的数据存储到字符/字节流指定文件中       使用这两个方法都需要 初始化相关的流对象       */         import java.io.*;      import java.util.*;    class PropertiesDemo1   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                   //将磁盘文件信息读取到资源类调用已有工具方法实现                            public static void readInfo1()  throws IOException                            {                            BufferedReader  br = new BufferedReader(new FileReader("info.txt"));  //初始化一个字符流读对象与目标地址相关联                                    Properties pro = new Properties();                          //初始化一个集合资源文件类用来存储信息                                                        pro.load(br);                                  //用来将目标地的文件信息加载进入 资源文件类                                                        pro.setProperty("winter","100");    //设置更改资源类中的键值对                                                        BufferedWriter bw =new BufferedWriter(new FileWriter("info.txt"));   //初始化一个字符流写对象与目标地址相关联                                                        pro.store(bw,"zhangxiaozong");     //将资源类中存储的信息写入到目标地址内,并且需要携带备注信息                                                        sop(pro);                                                                        }                                                 //将磁盘文件信息读取到资源类原理                            public static void readInfo()  throws IOException                            {                                                              BufferedReader  br = new BufferedReader(new FileReader("info.txt"));  //初始化一个字符流读对象与目标地址相关联                                                        String line=null;                                                        Properties pro = new Properties();   //初始化一个集合资源文件类用来存储信息                                                        while((line=br.readLine())!=null)   //遍历目标地信息                            {                                                              String[]  str =     line.split("=");    //以==为标识符切割                                                              pro.setProperty(str[0],str[1]);  //切割后以键值对的方式放入资源文件类                                                                                                }                                                        sop(pro);                                                                  }                                     //主方法                 public static void main(String args[]) throws IOException                        {                                                           //readInfo();                             readInfo1();                                             }          }                   


 
 
小结 :  

             1.  properties类操作数据的固定格式 :  键 = 值
                    2.  我们平时的操作是在内存中操作,程序一旦关闭,及恢复默认,若需永久更改,则需更改本地配置文件
       


    四十  五 .   IO流(Properties练习)
1 ) . 练习  :  用来设置程序可免费执行的次数
2 ) . Demo:


/*           本章讲述 :     练习 : 用于记录应用程序运行次数,若使用次数已到规定次数,则给出注册提示     思考条件:    [1]  次数自增 -->计数器       [2]  不随程序的结束而修改消失 -->存储硬盘配置文件    得出 : 用一个键值对的形式存储到硬盘上的配置文件,在程序开启时便加载即可  ,使用集合中的IO技术 : Map + IO =  properties类         */         import java.io.*;      import java.util.*;    class PropertiesDemo2   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                         //主方法                 public static void main(String args[]) throws IOException                        {                                                           Properties prop = new Properties();  //初始化资源类用来加载和存储信息                                                          File file =new File("S:\\develop\\JavaText\\info.properties");   //初始化文件类 用来指定地址                              if(!file.exists())   //判断文件是否存在                                    file.createNewFile();   //不存在则创建                                                                                        BufferedReader br =new BufferedReader(new FileReader(file));  //将文件放入字符流读的类中                                                         prop.load(br);   //将指定地址文件中的数据加载到资源类                                                         int count =0;   //定义计数器                                                          String value = prop.getProperty("count");   //获取本地文件类中count的值                                                        if(value!=null)  //判断值是否为空,不为空时进入操作                            {                                count = Integer.parseInt(value);  //将字符串换算为数值                                                                    if(count>=5)                                  {                                                                                  sop("您好,使用次数已到,请拿钱");                                  }                            }                                                         count++;  //为空时自动++                                                         prop.setProperty("count",count+"");  //将 计数器的键值 放入 资源类                                                                                     BufferedWriter bw =new BufferedWriter(new FileWriter(file));  //初始化文件字符流写的类                                                         prop.store(bw,"xiaoqinagqiang");  //资源类中的数据写入到字符流写的类中的指定文件地址                                                                         }          }                   


3 ) .  常见的两种配置文件 :  .properties  与 .xml
3.1    区别 :  .properties 讲究唯一性 ,最好存储 键值对都是唯一的  ;而  .xml中讲究多样性, 一个键可多个值 ,可操作关系复杂的情况

3.2   共同点 : .properties 与 .xml都是配置文件,而且 内格式都是 键值对
3.3 操作.properties的类是 properties  , 操作 .xml的类是 document  ,但是这个类不好操作,于是出现了   dom4j
3.4 dom4j 是 java的xml API,用来读写xml文件的

 

 
小结 :  

             1.  配置文件可以实现应用程序之间的共享
        
           2.  目前常见的两种配置文件:  .properties   与  .xml

       
 

       四十 六.  IO流(PrintWriter)

1 ) . IO包中的其他类 : 
1.1 打印流 :   PrintWriter与PrintStream  -->可以直接操作输入流和文件

1.2 序列流 :  SequenceInputStream  -->对多个流进行合并

1.3 操作对象 : ObjectInputStream与ObjectOutputStream  --> 被操作的对象需要实现Serializable(标记接口)

1.4 练习 : 文件分割程序

2 ) . Demo : 

/*     本章讲述 :   打印流 : 该流提供了打印方法,可将各种数据类型的数据都原样打印     分类:      1.字节打印流: PrintStream       构造函数可接收的参数类型 :              1.file对象,File              2.字符串路径 String              3.字节数据流  OutputStream       2. 字符打印流 : PrintWriter   -->常用        构造函数可接收的参数类型 :              1.file对象,File              2.字符串路径 String              3.字节数据流  OutputStream              4.字符输出流  Writer         小结 : 字符打印流的厉害之处在于 他的构造函数 可传 文件,我们常用字符打印流操作       */         import java.io.*;      import java.util.*;    class PrintWriterDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                         //主方法                 public static void main(String args[]) throws IOException                        {                             //初始化一个字符流读对象,并把源头设为 键盘输出                            BufferedReader br  =new BufferedReader(new InputStreamReader(System.in));                                                        //初始化一个输出写对象,并把目的设为控制台,并自动刷新                            // PrintWriter pw =new PrintWriter(System.out,true);   //这里加 true 的原因是 :  println,printf或format  使用时会自动刷新                                                        //初始化一个输出写对象,并把目的设为磁盘文件,并自动刷新                            PrintWriter pw =new PrintWriter(new FileWriter("1.txt"),true);                                                           String str=null;                                                         while((str=br.readLine())!=null)                          {                                          if(str.equals("over"))                                                 break;                                          pw.println(str.toUpperCase());  //将输出的内容大写                                                               }                                                  pw.close();                                                         br.close();                                             }          }                   

 

小结 :  

             1.   PrintWriter 直接对文件进行操作更加便捷
        
 

     四十  七.  IO流(合并流)
 

1 ) . 应用场景 : 多个文件数据合并成一个文件时用到合并流
2 ) .  Demo:

/*     本章讲述 :   合并流 : 该流提供了让多个流合并成一个流的方式,也就是让流串联起来          理解:                [1] 序列 :  就是有序的排列,指串联,比如合并流就是序列流,也是序列的一种体现方式 ,序列通常应用于 音乐信息                [2] 枚举 :  让各个对象的元素得以连续存入,一次一个                        SequenceInputStream : 合并流的方法                前提 :                [1] 需先将流对象存入Vector集合                [2] 采用vector集合中方法elements 让其元素得以连续,返回值是 枚举Enumeration                [3] 将元素放入序列流中进行排序合并为一流     */         import java.io.*;      import java.util.*;    class SequenceDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                         //主方法                 public static void main(String args[]) throws IOException                        {                                            Vector<FileInputStream> v  = new Vector<FileInputStream>();   //初始化一个用来装流的集合                                             //向集合内添加流对象                       v.add(new FileInputStream("summer.txt"));   //文件必须现实存在                       v.add(new FileInputStream("winter.txt"));                       v.add(new FileInputStream("spring.txt"));                        //将集合内的元素存入一个枚举类型泛型是读流的类中       -->枚举是得到连续数据的手段                       Enumeration<FileInputStream> en = v.elements();                                             SequenceInputStream sis  =new SequenceInputStream(en);  //初始化序列流对象,将刚才枚举对象中的流合并为一个流                                             FileOutputStream fos =new FileOutputStream("autumn.txt");   //初始化一个文件写出流                                                                byte[] buf =new byte[1024];   //定义临时存储区                      int len=0;                                            while((len=sis.read(buf))!=-1)      //读取序列流中数据                      {                             fos.write(buf,0,len);  //将序列流中数据读取到文件写出流中                                                  }                                           fos.close();  //关闭文件写出流                      sis.close();   //关闭序列流                                                                  }          }                   


 

小结 :  

             1.  多个源对应一个目标地时,采用合并流,合并流就是将流串联了起来,将最后一个流的返回值当做结束标识符
                
 
    四十  八 .  IO流(切割文件)   --> 重要
1 ) . 本章讲述了 切割与合并 ,合并最重要的是用 好 Enumeration枚举对象

2 ) . Demo:

/*     本章讲述 :   切割流 : 该流提供了让一个流切割成多个流的方式          切割原理 : 就是 拿一个容器,容器满了再换个容器,也就是换了个文件,具体实现通过while 循环+ close 关流操作 完成          当我们做合并流时,最重要的是使用SequenceInputStream ,而它 只接受参数 Enumeration  ,因此 需要放入集合,集合数据再放入Enumeration,然后Enumeration再放入SequenceInputStream             总结 : Java 获取Enumeration类型的集合方法  有两种:              [1] 通过vector集合获得,详细见上一章,但不高效                     [2] 通过List集合+iterator+匿名内部类的方法实现     */         import java.io.*;      import java.util.*;    class SplitDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                   //切割方法                            public static void splitFile() throws IOException                            {                                                                    FileInputStream fis  =new FileInputStream("S:\\develop\\JavaText\\Beyond.mp3");  //初始化文件读取流并关联地址                                                                    FileOutputStream fos = null;    //为文件写出流做外部引用                                                                    byte[] buf =new byte[1024*1024*3];   //定义一个数组容器,大小为3个MB                                                                     int len=0;    //用来临时存储数据                                                                    int count =0 ;   //用来为文件夹计数                                                                    while((len=fis.read(buf))!=-1)  //读取数据                                  {                                                                                  fos =new FileOutputStream("S:\\develop\\JavaText\\part\\Beyond"+(count++)+".part");  //初始化文件写出流并动态关联地址                                                                                  fos.write(buf,0,len);   //写入数据                                                                                  fos.close();    //关流,意味着 文件写出流中只有3MB数据写入到了文件中,再次循环则会再次创建文件                                                                           }                                                                                                                                        fis.close();                                                                                                }                                                                                    //合并方法                            public static void merge() throws IOException                            {                                                              ArrayList<FileInputStream> al =new ArrayList<FileInputStream>();  //初始化集合用来存文件读入流                                                                                    for(int i=0;i<=3;i++)                            {                                  al.add(new FileInputStream("S:\\develop\\JavaText\\part\\Beyond"+i+".part"));  //将文件读入流对象动态加入ArrayList集合                                                              }                            final  Iterator<FileInputStream> it = al.iterator();   //获取迭代器                                                                     //这里是通过匿名内部类的方式实现其所有抽象方法来完成实例化,Enumeration 与 ArrayList 的关联是 依靠 迭代器 ,请看 点击下边 it                             Enumeration<FileInputStream>  en =   new Enumeration<FileInputStream>()   //创建枚举对象,将集合中元素存入,以便序列流使用                            {                                  public boolean hasMoreElements()     //复写其测试此枚举是否包含更多元素的方法                                  {                                         return it.hasNext();                                  }                                  public FileInputStream nextElement()   //复写其如果此枚举对象至少有一个要提供的元素,则返回此枚举的下一个元素的方法                                  {                                         return it.next();                                  }                                                              };                            //------------以上都是为了获取下边的这一句合并流的类                                                        SequenceInputStream sis =new SequenceInputStream(en);   //获取序列流用来多流合一                                                                                    FileOutputStream fos =new FileOutputStream("S:\\develop\\JavaText\\part\\Beyond.mp3");  //初始化一个写出流并关联目标地址                                                                                                      byte[]  buf =new byte[1024];  //定义一个数组容器                                                                    int len=0;  //定义临时容器,用于判断是否到末尾                                                                    while((len=sis.read(buf))!=-1)  //向将序列流中的数据装入数组容器中                                  {                                                                                  fos.write(buf,0,len);  //将 数组容器中数据装入写出流的指定目标地中                                  }                                                                    fos.close();   //关闭写出流                                  sis.close();    //关闭序列流                                                                                                }                                                                                                                                                              //主方法                 public static void main(String args[]) throws IOException                        {                             //          splitFile();  //分割流方法                                         merge();             //合并流方法                         }                  }               


 

 
小结 :  

             1.  一个源对应是三个目标地是切割,三个源对应一个目标地是合并
                
          

    四十  九 .   IO流(对象的序列化)
1 ) . 序列化就是给对象起标识符存入介质的过程
2 ) . 案例解说 :  关于用户基本信息存储需要用到操作对象流的问题
2.1 初始化对象之后正常是存在内存中,程序结束之后调用GC进行垃圾回收,内存内数据消失 ;而 一些账户基本信息是不能消失的, 因此 要将其存入可持久化的介质(硬盘),这时 考虑到 IO流,但基本IO流是用来处理数据的,这时需处理对象, 需要用到 ObjectInputStream,ObjectOutputStrean 这是操作对象的流, 前提是 操作的对象需要被 序列化(实现serializable接口),也就是 为对象劳个章(起个UID,标识一下) 

3 ) .  Demo:

/*     本章讲述 :    操作对象的流对象  , 被操作的对象需要实现Serializable(标记接口)     [1] ObjectInputStream    : 用来读取对象     [2] ObjectOutputStream    : 用来写出对象     [3]Serializable  :  启用其序列化功能的接口,仅用来表示序列化对象       [4] transient :  该标识符标识到变量前,可让其变脸不参与序列化,但存在于堆内存中     [5] 一般存储序列化对象的文件名格式是 : 对象名.object       1.为何要序列化?     只有序列化后才可使用操作流对象,另外序列化后让对象存储时有一个uid去标识,这样在获取时方便        2.UUID是如何算出来的?                无论任何一个类中的属性参数其实都是具有标识的,UUID就是通过这些标识值算出来的,用来标识自己的类对象,因此唯一性非常之高      须知 :    [1]静态是不能被序列化的,序列化的是堆内的数据,而静态是在静态区中的     [2] 用ObjectOutputStream写出,必须  用他ObjectInputStream才能读入,两者成对存在的       */         import java.io.*;      import java.util.*;    class ObjectInputStreamDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                        //读对象方法                       public static void readObject() throws Exception                       {                              ObjectInputStream ois =new ObjectInputStream(new FileInputStream("obj.txt"));  //初始化一个对象读入流,并关联字节读入流的目标地址                                                          Person per =(Person) ois.readObject();  //读取目标地址中的对象与person关联                                                         sop(per);  //输出                                                    }                                                  //写对象方法                            public static void writeObje()  throws IOException                            {                                  ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("obj.txt"));  //初始化一个对象写出流,并关联字节写出流的目标地址                                                                    oos.writeObject(new Person("summer",13));  //初始化一个对象,将对象写入到对象写出流中,写出流会写入到关联的字节写出流的目标地址内                                                                    oos.close();  //关闭对象写出流                                                              }                                              //主方法                 public static void main(String args[]) throws Exception                        {                                                              //   writeObje();                                                                     readObject() ;                            }                    }       class Person implements Serializable  //对象的可串行化-->指对象序列化  //默认的实现此接口 会自动为该类赋予一个UUID,没初始化一次便更新一次UUID   {          public static final long serialVersionUID=42L;   //serialVersionUID : 这个名字是特定的,一旦写错则自定义UUID失败                   private String name;          transient  int age;    //意味着 该变量不被序列化                   Person(String name,int age)          {                               this.name=name;                this.age=age;          }                                    public void setName(String name)          {                this.name=name;                         }            public String getName()          {              return name;           }                                     public void setAge(int age)          {                this.age=age;          }                   public int getAge()          {                return age;                         }            }                 
 
小结 :  

             1.  对象的持久化就是将对象信息存储到可长期保存的介质上,也就是对象的序列化
        
           2.  我们可通过对象的系列化进行对象的重构,意味着将对象信息存储到硬盘,然后下次使用然后再读出来

           3. 没有方法的接口通常称为标记接口 ,比如  Serializable 可串行化接口

           4. 序列化的作用就是给类定义一个固定标识,就是为了使用操作对象流方便
 

       五十.  IO流(管道流)

1 ) . 简述 : 
1.1 RandomAccessFile

[1] 随机访问文件,自身具备读写方法

[2] 通过skipBytes(int x),seek(int x)来达到随机访问

1.2 管道流 :  PipedInputStream和PipedOutputStream

[1] 输入输出可以直接进行连接,通过结合线程使用
[2] 认识 : 以前的流需要输入流输出流两个流操作.并且两者没关系; 现在一个管道流就可搞定,内含输入输出


2 ) . Demo : 

/*     本章讲述 :  操作线程的流是 PipedInputStream与PipedOutputStream ,这两者之间可以相连接组成管道流         //测试read与writer两个线程的运行先后顺序 ,下边有输出语句用来测试 线程运行的先后顺序     */     import java.io.*;      import java.util.*;    class RandomAccessFileDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                        //主方法                 public static void main(String args[]) throws Exception                        {                                                             PipedInputStream in =new PipedInputStream();   //实例化管道流的读入流对象                                                             PipedOutputStream ou =new PipedOutputStream();  //实例化管道流的写入流对象                                                                                                                           Read rd =new Read(in);   //将读入流放入读方法                                                             Writer wr =new Writer(ou);  //将写入流放入写方法                                                                in.connect(ou);       //让其两个管道流相连接                                                                                            new Thread(rd).start();   //启动读方法                                                             new Thread(wr).start();   //启动写方法                                                                                                                                                      }                    }         //可写的线程对象    class Writer implements Runnable   {          private PipedOutputStream ou ;    //管道流的可写流 ,在可写线程一实例化变出现          Writer(PipedOutputStream ou)          {                this.ou=ou;                         }                   public void run ()  //启动线程的方法          {                try                {                      System.out.println("开始写入数据.......");  //测试read与writer两个线程的运行先后顺序                      ou.write("piped a lai le".getBytes());  //往管道流的写流中写入数据                                           ou.close();   //关闭可写流                                              }                catch(IOException e)                {                                             throw new RuntimeException("管道流读取失败");   //抛出异常                }                         }                     }     //可读的线程对象   class Read implements Runnable   {          private PipedInputStream in ;  //管道流的可读流 ,在可读线程一实例化变出现          Read(PipedInputStream in)           {                this.in=in;                         }                   public void run ()  //启动线程的方法          {                try                {                       byte[] buf= new byte[1024];   // 定义临时存储数据容器                                               System.out.println("读取前,目前没有数据产生");  //测试read与writer两个线程的运行先后顺序                       int len =in.read(buf);        //将读出的数据放入数组,并返回长度                         System.out.println("已读到数据,堵塞结束");  //测试read与writer两个线程的运行先后顺序                                             String s =new String(buf,0,len);  //将数据放入字符串                                             System.out.println(s);  //打印字符串                                             in.close();   //关闭可读流                                                            }                catch(IOException e)                {                         throw new RuntimeException("管道流读取失败");  //抛出异常                                      }                         }                     }


 

小结 :  

             1.  可以对接到一起的流对象就是管道流
        
           2.  集合当中涉及到IO流的是Properties , IO流当中涉及到多线程的就是PipedInputStream

     


       五 十一.  IO流( RandomAccessFile)
1 ) . RandomAccessFile  : 随机文件的读取和写入 -->其中涉及到一个案例是  下载软件的原理

2 ) . Demo:

/*     本章讲述 :       RandomAccessFile: 该类支持对随机文件的读取和写入       特点:    [1] 该类不是IO体系中子类,是Object的子类; 但由于它具备读写功能,因此是IO包中成员    [2] 该类内部封装了一个数据,可通过指针对数据的元素进行操作    [3] 该类可通过getFilePointer获取指针位置,通过seek改变指针的位置    [4] 该类通过构造函数可看出,只能操作文件,而且操作文件时还得传入模式参数:例如: 只读r ,读写rw等                  解析 : 他为何可完成读写?  因为内部封装了字节输入流和输出流                方法 :        seek(); 调整指针指向的坐标        skipBytes(); 跳过指定字节数        write();  向随机访问流对象内写数据        read();   读取随机访问流对象的数据                小结 :                [1] 若模式为只读r,则不会创建文件,会去读取一个已存在文件,若该文件不存在,则会出现异常                [2] 若模式为读写rw,操作的文件不存在时,会自动创建,若存在则不会覆盖           */     import java.io.*;      import java.util.*;    class RandomAccessFileDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                    public static void getRead()throws Exception                            {                                     RandomAccessFile raf =new RandomAccessFile("ran.txt","r");  //初始化随机访问流对象                                                                        //该方法是调整指针,动态的获取文件中任何地方的数据,前提是文件中的数据有规律                            //     raf.seek(8*0);   //这里存储的数据是 8 个字节的 ,若要让指针指到下一个坐标,即可获取下一个 8字节的数据 *2即可                                                                    //跳过指定字节数                                  raf.skipBytes(8);                                                                                                                                        byte[] buf =new byte[4];                                                                     raf.read(buf);   //可用来读取字节的方法                                     String name =new String(buf);                                                                        int age =    raf.readInt();   //专门用来读取int数据类型的方法                                                                     sop(name+"::"+age);                                                                     raf.close();                                                              }                                                        public static void getWrite()throws Exception                            {                                                                      RandomAccessFile raf =new RandomAccessFile("ran.txt","rw");                                                              raf.write("张三".getBytes());                                                                                                                              //raf.write(97);   //默认是char类型接收,即97占一个字节                                                                    raf.writeInt(97);  //char类型向上提升为int,即占4个字节, 这样的好处是让字母与数字之间有了距离                                                             raf.write("李四".getBytes());                                                               raf.writeInt(99);                                                                              raf.close();                                                          }                    //主方法                 public static void main(String args[]) throws Exception                        {                     //        getWrite();                             getRead();                                                                                          }                    }        


3 ) .  关于一个字符占几个字节 : 
3.1 ASCII码表中 : 

[1] 一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间

3.2 UTF-8中 : 

[1] 一个英文字符等于一个字节,一个中文(含繁体)等于三个字节

3.3 Unicode编码中:

[1] 一个英文字符等于两个字节,一个中文 (含繁体) 等于两个字节

3.4 关于符号是 : 英文标点占一个字节,中文占两个字节

 

小结 :  

             1.  随机读写访问类可实现软件任务多线程的下载   ;   思想 :  将数据分为几段, 一个线程负责一段,即可完成同时下载  -->这就是下载软件的原理
                    2.  若存储某事物时容量不确定时,尽量给最大容量,避免出现内存溢出 ;  例如  : 名字  , 中国人名字最长也就4个字, 当然还有 少数民族 有可能 6个字,那么给 16个字节即可
         
          
 
    五  十二 .  IO流( 操作基本数据类型的流对象DataStream)
1 ) . IO包中的其他类 : 
1.1 DataInputStream与DataOutputStream  -->操作基本数据类型

1.2 ByteArrayInputStream与ByteArrayOutputStream  -->操作字节数组

1.3 CharArrayReader 与CharArrayWrite  --> 操作字符数组

1.4 StringReader 与 StringWriter -->  操作字符串

2 ) . Demo:

/*     本章讲述 :     DataInputStream与DataOutputStream : 可以用于操作基本数据类型的数据的流对象        须知 : DataOutputStream 写入的数据 必须 DataInputStream 读出,否则会出现乱码           */     import java.io.*;      import java.util.*;    class DataStreamDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                            //读入UTF-8修改版的编码格式的数据                      public static void readUTF() throws IOException                      {                             DataInputStream dis =new DataInputStream(new FileInputStream("demoUTF.txt"));                                                        String summ= dis.readUTF();                                                        sop("summ:"+summ);                                                                              }                      //以UTF-8的修改版的编码格式写出                             public static void writeUTF() throws IOException                      {                              DataOutputStream dos = new DataOutputStream(new FileOutputStream("demoUTF.txt"));                                                         dos.writeUTF("sumer");                                                  }                                             //写出数据类型相关的数据                      public static void writeData() throws IOException                      {                            DataOutputStream dos = new DataOutputStream(new FileOutputStream("demo.txt"));//初始化数据类型输出流对象                                                        dos.writeInt(99);                            dos.writeBoolean(true);                            dos.writeDouble(98.2342);                                                        dos.close();                                                                                                          }                                           //读入数据类型相关的数据                      public static void readData() throws IOException                      {                                                         DataInputStream dis =new DataInputStream(new FileInputStream("demo.txt"));  //初始化数据类型输入流对象                                                        int num= dis.readInt();   //写入int类型的数据                                                        Boolean bol = dis.readBoolean();                            Double dou =dis.readDouble();                                                        sop(num+"::"+bol+"::"+dou);                                                                              }                    //主方法                 public static void main(String args[]) throws Exception                        {                                         /*                                                演示读入写出数据类型相关数据的流                                         */                                         //writeData();                                         //readData();                                                                                                                           /*                                                演示读入写出数据类型相关数据的流的其它字符写入流                                         */                                  //     writeUTF();                                         readUTF();                                                              }                    }    

 
 
小结 :  

             1.  UTF-8一个中文字3个字节,但UTF-8的修改版中是一个中文字4个字节
                    2.  往后若只操作相关数据类型的流对象则用 Data...Stream
        
          

      五 十三 .   IO流(ByteArrayStream) --> 重点
1 ) .  ByteArrayStream 该对象是数组与流对象的封装,使用方便
2 ) . Demo:

/*     本章讲述 :     ByteArrayStream : 用于操作字节数组的流对象,底层封装的是 可变长度字节数组    ByteArrayInputStream :在构造的时候,需要接受数据源,而且数据源是一个字节数组    ByteArrayOutputStream : 在构造的时候,不用定义数据目的,因为该对象内部封装了可变长度的字节数据,因此这就是数据目击地 特点 : 该对象不涉及系统资源,因为都是在内存中操作数组,所以close也不用关闭 总结 : 流操作规律讲解 : 源设备 :        键盘 : System.in.  硬盘 FileStream  内存  ArrayStream 目的设备:        控制台: System.out  硬盘 FileStream  内存 ArrayStream   */     import java.io.*;      import java.util.*;    class ByteArrayStreamDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                               //主方法                 public static void main(String args[])                        {                                   //数据源                                   ByteArrayInputStream bais =new ByteArrayInputStream("ASDFGH".getBytes());                                    //数据目地                                   ByteArrayOutputStream baos =new ByteArrayOutputStream();                                                                     int by=0; //临时存储变量                                                                     while((by=bais.read())!=-1)  //读数据                                   {                                                                                   baos.write(by); //写数据                                   }                                                                     sop(baos.size());  //获取数组大小                                   sop(baos.toString()); //以字符串的形式打印数组内容                                                              //将数据写入磁盘文件  baos.writeTo(new FileOutputStream("rellay.txt"));                                                               }                    }    

 
小结 :  

             1.  对数组的操作就是 设置和获取  ,同样对流的操作时   写 和读
        
        
 

       五 十四.  IO流(转换流的字符编码)

1 ) . 简述 : 字符编码
1.1 字符流的出现为了方便操作字符 ,更重要的是加入了编码转换

1.2 通过子类转换流来完成:

[1] InputStreamReader

[2] OutputStreamWriter

1.3 在两个对象进行构造的时候可以加入字符集

2 ) . 可以玩编码表的流 : 
2.1 转换流:

[1]  InputStreamReader

[2] OutputStreamWriter

2.2 打印流:

[1] printWriter

[2] printReader

3 ) .  编码表的由来 : 
3.1 历程 : 开关开关的电信号-->1010的二进制 -->1010与不同国家的不同文字相对应而形成了一张表  --->这张表就是编码表

3.2 分类 :
[1] ASCII : 美国标准信息交换码 :  用一个字节的七位可以表示

[2] ISO8859-1: 拉丁码表.欧洲码表 : 用一个字节的8位表示

[3] GB2312 : 中国的中文编码表: 用两个字节的16位表示

[4] GBK : 中国的中文编码表升级融合了更多的中文文字符号

[5] Unicode : 国际标准码表,融合了多国文字 : 所有文字都是用两字节表示,java语言使用的就是unicode

[6] UTF-8 : 最多用三个字节来表示一个字符-->也就是 可用一个字节,也可用两个字节,最多用三个字节 

4 ) . DEmo:

/*     本章讲述 :           [1] OutputStreamWriter  :  写出的字符字节转换流,其构造方法可指定编码                [2] InputStreamReader   : 读入的字符字节转换流,其构造方法可指定编码       总结  :  GBK编的码 用UTF-8去读则会出现 ?? 的乱码;  UTF-8编的码用GBK去读则会出现类似繁文的文字       */     import java.io.*;      import java.util.*;    class EncodeStream   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                                  public static void writeText() throws IOException                            {                                  OutputStreamWriter osw =new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8");                                                                                                       osw.write("你好");                                                                    osw.close();                                                              }                                                          public static void readText() throws IOException                            {                                  InputStreamReader isr =new InputStreamReader(new FileInputStream("demo.txt"),"GBK");                                                                    char[] buf =new char[1024];                                                                    int len =isr.read(buf);                                                                    String str =new String(buf,0,len);                                                                    sop(str);                                                                    isr.close();                                                              }                                                                 //主方法                 public static void main(String args[])  throws IOException                        {                                                                                                      // writeText();                                  readText();                                                              }                    }    



小结 :  

             1.  UTF-8编的码拿着GBK解码这时会出现繁体乱码;   GBK编的码拿着UTF-8解码这时会出现??乱码
      


       五 十五.  字符编码
1 ) . 字符编码就是字符串与字节数组来回转换的过程

2 ) . Demo:

/*     本章讲述 :      编码 : 字符串编程字节数组     解码 : 字节数组变成字符串     String--> byte[];   str.getBytes(charsetName);     byte[]  --> String : new String(byte[],cahrsetName);       */     import java.io.*;      import java.util.*;    class EncodeDemo   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                        //主方法                 public static void main(String args[])  throws IOException                        {                                   String s = "你好";                                                                    byte[] b1 = s.getBytes("UTF-8"); // 编码                                                                    sop("编码输出:"+Arrays.toString(b1));  //输出编码内容                                                                    String str =new String(b1,"GBK");  //解码                                                                  sop("解码输出:"+str);   ///解码失败,因为编码的码表与解码的码表不是一张表,一个UTF-8,一个GBK                                                                    byte[] b2 = str.getBytes("GBK");  //反向编码                                                                    sop("反向编码输出:"+Arrays.toString(b2));                                                                    String str2 = new String(b2,"UTF-8"); //再次解码                                                                    sop("解码输出:"+str2);   //解码成功,因为编码的码表与解码的码表是一张表,是UTF-8                                                                                          //结论 :  拿什么编的码就得拿什么解码  ,若出现编码失败,则反向编码出原来内容即可,再次重新解码即可                                                              }                    }      


3 ) .  重点 : 
3.1 当我们是get请求时 , 解决乱码的方式就是 再次 反向编码

 

 

小结 :  

             1.  所谓的数据编码及解码就是对数据的来回    转换
                    2.  Tomcat服务器的默认编码格式是ISO8859-1 
           3  .我们通常会用到的码表是  GBK  ,ISO8859-1 ,UTF-8
           4. 项目中要统一编码格式
          
 
    五  十六 .  字符编码-联通
1 ) . 字符编码 : 明白UTF-8的编码怎么判断何时读一字节,何时读两字节,何时读三字节的, 当我们换算为 二进制时,是依靠二进制前的标识符判断的

2 ) . Demo:

/*     本章讲述 :     Integer.toBinaryString() :用来将字符串换算为二进制    &255 : 用来取二进制的有效位,也就是后八位    小结 :    当字节前的标识符是111时,便一次读三个字节  当字节前的标识符是11时,便一次读两个字节  当字节前的标识符是1时,便一次读一个字节         */     import java.io.*;      import java.util.*;    class EncodeDemo1   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                        //主方法                 public static void main(String args[])  throws IOException                        {                                                                                                       String str ="联通";                                                                     byte[] buf = str.getBytes("GBK");                                                                     for(byte b : buf)                                   {                                                                                   sop(Integer.toBinaryString(b&255));                                   }                                                                                                }                    }      

 
小结 :  

             1.  转码的过程 : 字节数据--><--编码表 -->生成 对应符号  
                    2.  UTF-8的编码数据中有标识头信息,用来标识是读1个字节还是2个字节还是3个字节 
[1] 当标识头是111时,便向下读两个字节+自身 =3字节

[2] 当标识头是11时,便向下读1个字节+自身 =2字节

[3] 当标识头是1时,便读自身即可也就是1字节

     
          

  五  十七 .  练习
1 ) . 以下输入数据,处理数据(数据排序),存入磁盘的过程

2 ) . Demo:
/*     本章讲述 :    需求 :   有五个学生,每个学生有三门课的成绩,从键盘输入以上数据(包括姓名,三门课成绩)   输入的格式:  如: 张三,30,40,60计算出总成绩   并把学生的信息和计算出的总分数高低顺序存放在磁盘文件的"stud.txt"中      实现步骤 :        [1] 描述学生对象        [2] 定义一个可操作学生的工具类                思想:        1.通过获取键盘录入一行数据,并将该行的信息取出封装成对象        2.因为学生量大,因此需要存储集合,又因需总分排序,则需要TreeSet        3.通过IO流的方式将集合的信息写入到一个文件中                                总结 :        [1] HashSet底层是哈希表结构,依赖的是HashCode和Equals                [2] TreeSet底层是二叉树结构,依赖的是CompareTo                用到的方法:                [1] Comparable接口中的compare()方法 : 用来为指定数据进行排序                [2] equals()方法 : 默认排序                [3] TreeSet集合:存储可排序的数据                [4]BufferedReader :  用来加强读入IO流数据的临时容器                [5] InputStreamReader: 字符流与读字节流之间的转换器                [6]System.in  : 用来在dos窗口输入数据的方法                [7]split  : 字符串的数据切割                [8]BufferedWriter : 用来加强写出IO流数据的临时容器                [9]FileWriter: 用来写出数据的IO字符流                [10]compareto   :比较器当中的比较方法                [11] Collections.reverseOrder() : 集合工具类当中让已排序的数据按逆序排列的方法                           */     import java.io.*;      import java.util.*;      //该类当中默认使用equals , 优先使用compareTo   class Student implements Comparable<Student>  //可操作对象   {          private String name;          private int ma,cn,en;          private int sum;                   Student(String name,int ma,int cn,int en)          {                this.name=name;                this.ma=ma;                this=cn;                this.en=en;                this.sum=ma+cn+en;                         }                            public int compareTo(Student s)  //实现比较器          {                int num =new Integer(this.sum)pareTo(new Integer(s.sum));  //比较总成绩                if(num==0)                       return this.namepareTo(s.name);                return num;                         }                   public String getName()          {                return name;                                        }          public int getSum()          {                               return sum;          }                                              public int hashCode()  //这个方法在此过程中不具备意义,只是考虑若使用set存储该对象则需要实现此方法          {                               return name.hashCode()+sum*78;  //          }                   public boolean equals(Object obj)            {                if(!(obj instanceof Student))                       throw new ClassCastException("类型不匹配");                Student s = (Student)obj;                               return this.name.equals(s.name) && this.sum==s.sum;   //返回名字和成绩总和                         }                   public String toString()          {                return "student["+name+","+ma+","+cn+","+en+"]";                         }                              }     //操作学生的工具类   class StudentInfoTool   {           //将数据写入并放入集合的方法          public static Set<Student> getStudents() throws IOException   //该方法是下边方法的抽取版本,下边方法是此方法的完善版本 -->理解 : 一个          {                       return getStudents(null);          }                            //将数据写入并放入集合的方法          public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException          {                BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));  //初始化一个缓存区写入流用来写入数据                               String line= null;                Set<Student> stus= new TreeSet<Student>();  //初始化一个临时存储集合                               if(cmp==null) //判断是否传入比较器,若传入则初始化传入的TreeSet集合                       stus= new TreeSet<Student>();                else                       stus= new TreeSet<Student>(cmp);                               while((line=bufr.readLine())!=null)  //将数据放入集合的方法                {                       if("over".equals(line))                              break;                                           String[] info =  line.split(",");  //将数据切割                                          Student st =new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3]));                                             stus.add(st);  //切割后的数据放入集合                                                           }                bufr.close();  //关流                               return stus;  //返回集合中的数据                         }                            //将集合中的数据通过IO流放入本地文件的方法          public static void write2File(Set<Student> stus)  throws IOException          {                BufferedWriter bufw =new BufferedWriter(new FileWriter("stuinfo.txt"));                               for(Student stu:stus)                {                       bufw.write(stu.toString()+"\t");                       bufw.write(stu.getSum()+"");                       bufw.newLine();                       bufw.flush();                                      }                               bufw.close();                         }                              }     class EncodeText   {                   public static void sop(Object obj)               {                            System.out.println(obj);               }                                        //主方法                 public static void main(String args[])  throws IOException                        {                               //用来将下边集合中的数据的排序逆序的方法                               Comparator<Student> cmp = Collections.reverseOrder();                                  //通过工具类调用输入流的方法用来输入数据,并将输入的数据放入集合                                  Set<Student> stus = StudentInfoTool.getStudents(cmp);                                   //将数据通过流写出到本地磁盘文件的方法                                   StudentInfoTool.write2File(stus);                                                              }                    }      

  

 


本文标签: (十二)Core Java IO流(Properties 序列化 管道流 字符编码)