黑马程序员——38,IO流(字符流)

----------- android培训java培训、java学习型技术博客、期待与您交流!------------      

黑马程序员——38,IO流(字符流)      

一:Filewriter----》

        IO流用来传输数据,相关流放在java.io包中。原本数据传输都是传输字节流,但是后来因为传输字符的要求,所以,又有一个字符流,字符流是与编码表相关的流,而字节流一般都是用在图片或者媒体文件上。

        字节流的抽象基类是InputStream和OutputStream,而字符流的抽象基类是:Reader和Writer

        比较常见的是FileWriter和FileReader,FileWriter是一个用来写入数据的流,的使用如下例子,注意要刷新流里面的数据,这样才可以把数据传倒目的地。而字节流是没有刷新操作的,都是直接通过流输入到目的地。

FileWriter的使用步骤:

1,先建立Filewriter流对象

2,write写入数据

3,Filewriter没有自动刷新功能,记得用flush刷新

4,close关闭资源


import  java.io.*;
class  Ioliou
{
         public    static   void main(String[] args)throws IOException
                   //IO流代码后容易抛出异常,所以一般都会在方法上抛出IOException
         {
                   FileWriter  f=new FileWriter("f:\\yyyyyyy.txt");//直接指定文件
                   //FileWriter是用于操作文件的Writer类的子类对象
                   /*
                   这句话可以指定路径建立对应名字的文件,
                   如果指定路径中已经存在同名文件,那么原本文件会被新建文件覆盖掉。
                   */
                
                   f.write("jkl"); //将字符串写入流中
                    /*
                    但是此时如果打开yyyyyyy.txt文件看的话发现里面并没有写入jkl
                    这是为什么呢?因为其写入的仅仅是流中,不是写入文件中
                   */
                    f.flush();//刷新流,把流里面的数据刷新到目的地
                    /*
                    此时再打开yyyyyyy.txt文件就会看见写入的jkl
                    */
                    f.close();//这句话作用是先刷新流,接着再关闭流
                    f.write("rty");//由于前面关闭了流,所以这句话是写不进流里面的
                   System.out.println("Hello World!");
         }
}

        但是这种方式会导致如果有同名文件,那么就被新文件覆盖的情况,如果不想被覆盖掉的话,就可以使用另外一种FileWriter的构造函数:FileWriter(String  s,boolean b)  表示可以在原有文件后面续写数据。还有如果在写入的数据中需要换行的话用到\r\n                  


文件的续写:

importjava.io.*;
class  Ioliou3
{
         public static  void   main(String[] args)
         {
                   FileWriter  fi=null;
                   try
                   {
                   fi=new  FileWriter("f:\\trtrtr.txt",true);
                   /*
                   因为新建文件会覆盖原有文件,所以,FiletWriter类提供一个构造函数
                   FileWriter(String  s,boolean b)  表示可以在原有文件后面续写数据                    
                   */
                   fi.write("我是\r\n英雄");
                   /*
                   这句话表示输入数据“我是”然后换行接着输入数据“英雄”。
                   为什么要在\n前面加上\r呢?因为\r\n写在一起在window系统里面才表示换行,
                   仅仅是\n只是在java里面才表示换行。如果写的是fi.write("我是\n英雄");
                   那么在java里面显示的确是会换行。但是用window系统里面的工具打开,
                 “我是”与“英雄”之间会有一个黑块,这是window系统无法识别单独的\n的原因。
                   */                      
                   }
                   catch(IOException   e)
                   {
                    soc(e.toString());                                
                   }
                   finally
                   {
                            try
                            {
                                    fi.close();     
                            }
                           catch(IOException  e)
                            {
                                    soc(e.toString());
                            }
                   }
                  System.out.println("HelloWorld!");
         }
         public static  void  soc(Object obj)
         {
             System.out.println(obj);                             
         }
}

二:FileReader----》

        FileReader是用来读取数据的,读取的方式通常是用read方法来读取的。因为io流经常会抛出异常对象,所以会用一种针对异常的机制处理,这个后面会介绍。

FileReader的使用步骤:

1,先建立FileReader流对象

2,read读取数据

3,close关闭资源

import     java.io.*;
class    Ioliou4                 
{
         public     static   void     main(String[] args)
         {
                   FileReader     re=null;
                   try
                   {
                   re=new     FileReader("f:\\trtrtr.txt");
                   /*
                   建立一个文件读取流对象,并且指向已经存在的文件!
                   如果文件不存在,运行会发生FileNotFoundException
                   */
                   while(true)//无限循环,编译运行必要时候要按Ctrl+c停止
                      {
                          
                        int  i=re.read();
                             char ch=(char)i;
                        soc(ch);
                             if(i==-1)
                        break; 
 
                             int  i2=re.read();
                             /*
                             read方法一次读取一个字符,返回的是int型数据,可以自动往下读取,
                             而且如果后面读到没有数据可读的时候就会返回-1,如果被强制转成字符打印出来的是一个问号?
                        */
 
                        char   ch2=(char)i2;
                        soc(ch2);
                             if(i2==-1)
                   break;
                       }
                   }
                   catch(IOException  e)
                   {
                            soc(e.toString());
                   }
                   finally
                   {
                            try
                            {
                                    re.close();//仅仅是关闭流     
                            }
                           catch(IOException  e)
                            {
                                    soc(e.toString());
                            }
                                
                   }
 
         }
         public static  void  soc(Object obj)//打印方法
         {
                System.out.print(obj);               
         }
}

        这种读取数据的方式并不高效,所以一般都是read方法配合数组来读取数据,把数据装在数组里面,装满之后读取再装再读取,直到数据读取完为止。

importjava.io.*;
class  Ioliou5
{
         public   static void   main(String[] args)
         {
            FileReader   fr=null;
            try
            {
                fr=newFileReader("f:\\trtrtr.txt");
                char[]  ch=new char[5];
                   int     i =0;
                   while((i=fr.read(ch))!=-1)
                   {
                   soc(new String(ch,0,i));
                   /*
                 new  String(ch,0,i)表示新建一个字符串,
                 其内容为字符数组ch的从0位开始长度为i的字符组成。
             */   
                   }
                 
                   }
                   catch(IOException  e)
                   {
                      soc(e.toString());
                   }
                   finally
                   {
                            try
                            {
                               fr.close();
                            }
                           catch(IOException   e)
                            {
                               soc(e.toString());
                            }
                      
                            
           }
 
         }
 
         public static void  soc(Object  obj)
         {
             System.out.println(obj);                        
         }
}

        按照字符数组长度来读取,返回的是读取到的字符个数,例如在本题中,长度为5的字符数组,读取的时候从第一位到第三位;填充字符,填充完了就返回填充的个数;再次调用read方法的时候,会自动往下继续读取字符,又从第一位到第三位重新填充字符。

        如果在某一次填充字符过程中,字符数组还没有填充完就没有字符继续填充的情况下,这一次返回的是本次填充字符的个数,返回值也许不是字符数组长度。

        如果在某一次填充字符过程中,字符数组还没有填充完就文件字符换行的情况下,本次就只是填充到换行处,返回本次填充字符个数,下一次填充字符又从第一位开始填充下一行的字符。再接下来,继续调用read方法读取,在上一次已经全部读取完字符了,那么这一次,返回值-1而读取一些比较大的文件的时候,一般定义字符数组长度1024,这样是比较方便的。

       有了FileReader和FileWriter的配合使用就可以达到数据传输的效果。

       复制小练习:把文件从f盘复制到d盘。

      一般复制文件的步骤是先建立读取流指定读取文件,指定写入流写入目的地,然后调用相关的write方法和read方法配合数组一边读取一边写入,复制完后记得关闭资源。

该习题为了配合异常处理机制的介绍,放在了后面。

 

三:异常处理机制----》

        以上的例子就用到了异常处理机制try…catch…模块,这就是用来处理异常对象的机制,有了这个机制就不需要在方法上声明有异常。

try
{
       //被检测的语句
}
catch(异常类型    异常变量)
{
      //处理异常的语句          
}
finally
{
     //无论是否有异常都一定要执行的语句,通常用于关闭资源,但是finally块前面有System.exit(0);表示退出程序的话,那么finally块就不会执行到了,程序强制退出。            
}

以下是各个语句块之间相互配合使用:

//try…catch…一般仅仅用来处理异常
try
{
    //被检测语句   
}
catch(异常类型   异常变量)
{
    //异常处理语句          
}
 //分割线---------------------------------------------
 
try
{
         //被检测语句   
}
finally
{
      //一定会执行的语句,通常用来关闭资源
}
 

        需要注意的是:每一个语句块都是变量的作用域,如果有变量定义在以上某个语句块中,那么有效作用区域就只有该语句块中,所以,如果该变量在其他语句块中也要用到的话,就把该变量一开始定义在外面,复制小练习所示:

importjava.io.*;
class   Ioliou6
{
         public static void  main(String[] args)
         {
            FileWriter  fw=null;//把变量定义在语句块外面,这里就是局部变量,有效作用域是这个main方法
            FileReader  fr=null;
             try
             {
               fw=newFileWriter("d:\\trtrtr_copy.txt");
               //建立一个写入流对象,指定存储的路径的文件
               fr=newFileReader("f:\\trtrtr.txt");
              //建立一个读取流对象,与目的地相关联
                char[]  ch=new char[1024];
                int i=   0;
                 while((i=fr.read(ch))!=-1)
                 {
                    fw.write(ch,0,i);
                                     /*
                    按照字符数组ch从0位开始长度为i把字符写进流中
                           */
 
                 }                         
             }
                   catch(IOException  e)
                   {
                       throw  new RuntimeException("读写出问题了");
                             //抛出一个运行异常对象
                   }
                   finally
                   {
                            try
                            {
                               if(fw!=null)
                               fw.close(); //close也会抛出异常,这里也有try…catch处理一下
                            }
                           catch(IOException  e)
                            {
                      
                            }
                       try
                       {
                            if(fr!=null)
                            fr.close();
                       }
                       catch (IOException  e2)
                       {
                    
                       }
                          
                   }
 
                 
         }
         public  static void soc(Object  obj)//打印
         {
               System.out.println(obj);                   
         }
}
 

四:BufferedWriter----》

        对于一些大的文件,我们也可以使用字符流缓冲技术。缓冲区技术是在流的基础上(必须要先有流的存在)增强了流对于数据的操作效率。打个比喻就是原本是在水龙头上一滴一滴的喝水,但是现在则是拿着杯子喝水。

我们先介绍BufferedWriter。

使用BufferedWriter的一般步骤如下:

1,先建立流对象

2,建立缓冲区对象,把流流对象放进缓冲区

3,write写入数据

4,BufferedWriter没有自动刷新功能,记得用flush刷新,BufferedWriter还有一个newLine方法用来换行的,如果有需要也可以使用。

5,close关闭资源

importjava.io.*;
class   Ioliou7
{
         public   static void   main(String[] args)
         {
                   FileWriter   fw=null;
                   BufferedWriter    bfw=null;
                   try
                   {
                      fw=newFileWriter("f:\\yuyuyu.txt");
                      bfw=newBufferedWriter(fw);
                   //把写入流对象传给缓冲区构造函数
                      bfw.write("假面骑士01号登场!");
                   //实际上把字符写入流的还是fw调用底层资源实现的
                   bfw.newLine();
                   //换行
                     bfw.write("假面骑士02号登场!");
                      bfw.flush();
                   //这里还是要刷新才把存在流的数据传倒文件里面
                 
                   }
                   catch(IOException  e)
                   {
                            throw   new RuntimeException("写操作有误");
                   }
                   finally
                   {
                            try
                            {
                            if(bfw!=null)
                            {
                          bfw.close();
                          //关闭流,
                   /*
                   bfw.close();本质上关闭流的还是fw底层调用close()方法实现的,
                   所以就不用再写fw.close();了
                   */             
           }                                  
                            }
                           catch(IOException   e)
                            {
                                     throw  new RuntimeException("bfw.close();出问题抛出异常了");
                            }
                   }
 
         }
         public static void  soc(Object  obj)//打印方法
         {
             System.out.println(obj);                            
         }
}
 

五:BufferedReader----》

使用步骤和BufferedWriter类似:

1,建立于目的地关联的流对象

2,建立BufferedReader缓冲区,把目的地关联的流对象放入BufferedReader的构造函数中

3,用readLine读取数据

4,关闭资源

import  java.io.*;
class  Ioliou8
{
         publicstatic void main(String[] args)
         {
                   FileReader   fr=null;
                   BufferedReader   bfr=null;
                   try
                   {
                      fr=new FileReader("e:\\JAVAwenjian\\Ioliou8.java");
                      bfr=new   BufferedReader(fr);
                 
                   String   s=null;
                  while((s=bfr.readLine())!=null)
                   /*
                   readLine()一行一行的读取,不包含任何行终止符,如果没有数据读取就返回null,
                   但是不返回回车符,所以输出打印或者写入的时候要记得换行。
                   readLine读取数据本质上还是要调用read方法一个一个读取的
                   */
                   {
                      soc(s);
                   }
                           
                   }
                   catch(IOException  e)
                   {
                            throw  new RuntimeException("读操作出问题");
                   }
                   finally
                   {
                        try
                        {
                                     if(bfr!=null)
                                       bfr.close();
                        }
                        catch (IOException  e)
                        {
                                throw new RuntimeException("读操作出问题");
                        }
                   }
 
         }
         public static void  soc(Object  obj)
         {
             System.out.println(obj);                               
         }
}
 

        有了以上BufferedWriter和BufferedReader,就可以更加方便的复制文件:

        把e:\\JAVAwenjian\\Ioliou8.java复制到d盘中

import  java.io.*;
class  Ioliou9
{
         public   static void  main(String[] args)
         {
         FileWriter  fw=null;
         FileReader  fr=null;
         BufferedWriter  bfw=null;
         BufferedReader  bfr=null;
       try
       {
                     fw=newFileWriter("d:\\Ioliou8_copy.java");//建立字符流写入对象
                     fr=newFileReader("e:\\JAVAwenjian\\Ioliou8.java");//建立字符流读取对象
                     bfw=new  BufferedWriter(fw);//建立字符流写入缓冲区
                     bfr=new  BufferedReader(fr);//建立字符流读取缓冲区
 
                    String   s=" ";
                    while((s=bfr.readLine())!=null)
                     {
                       
                       bfw.write(s);
                            bfw.newLine();//换行
                     }
      
                          
       }
       catch (IOException  e)
       {
                            throw   new RuntimeException("复制操作出问题");
       }
                   finally
                   {
                            try
                            {
                                    if(bfw!=null)
                                      bfw.close();
                            }
                           catch(IOException  e)
                            {
                                     throw  new RuntimeException(" bfw.close();出问题");
                            }
                     try
                     {
                              if(bfr!=null)
                                      bfr.close();
                     }
                     catch (IOException  e2)
                     {
                              throw newRuntimeException("bfr.close();出问题");
                     }
                 
                   }
 
 
         }
         public static  void  soc(Object obj)
         {
             System.out.println(obj);                         
         }
}
 

六:装饰类----》

        装饰类,也称为装饰设计模式。通常是自定义一个类,通过构造函数传入已有的对象,增强功能,装饰类和被装饰类都有着相同的功能,只不过,装饰类具备更强的功能。

一般装饰类与被装饰类处于同一个体系中,装饰类最好要覆盖好父类的抽象方法,注意是否有异常抛出。

以下是建立MyBufferedReader的例子:

import    java.io.*;
class  MyBufferedReader  extends Reader//继承Reader类
{
         private   FileReader fr=null;//设定为全局变量,作用域是整个类
         MyBufferedReader(FileReader   fr)//传进来一个FileReader流的对象
         {
                this.fr=fr;              
         }
         StringBuffer   sb=new   StringBuffer();
         public String   readLine()throws  IOException//注意异常的抛出
         {
                   char  ch=' ';
                   int  i=0;
                   while((i=fr.read())!=-1)//这里就是内部调用传进来的对象的方法
                   {
                       //因为Windows系统里面认为\r\n组合起来才是一个回车符
                        if(i=='\r')
                           continue;
                        if(i=='\n')
                        return  sb.toString();
                         ch=(char)i;
                         sb.append(ch);//append是在后面添加字符,没有覆盖前面字符
                 
             }
                   if(sb!=null)
                   return  sb.toString();
                   return  null;
         }
         public void  close()throws  IOException
         {
              fr.close();        
         }
         public static void  soc(Object  obj)
         {
               System.out.println(obj);
         }
         //下面记得要覆盖Reader类中的抽象方法
 
         public   int  read(char[]   cbuf,int off,int len)throws  IOException
         {
                   return   fr.read(cbuf,off,len);
                             
         }
 
}

        还有一个比较常用的流LineNumberReader,这是BufferedReader的子类,基本功能和BufferedReader差不多,只是添加了setLineNumber方法可以设置行数开始计数读取的行数,然后getLineNumber方法获取当前读取数据时候的行数是第几行。

import   java.io.*;
class  Ioliou12
{
         public static   void  main(String[] args)
         {
                   FileReader          fr=null;
                   LineNumberReader   lnr=null;
                   try
                   {
                      fr=newFileReader("Ioliou12.java");
                   //建立读取流对象
                      lnr= new  LineNumberReader(fr);
                 
                   String   s=" ";
                   lnr.setLineNumber(123);
                   //设置行号从123的后一行开始
                   while((s=lnr.readLine())!=null)
                   {   
                       soc(lnr.getLineNumber()+":"+s);
                       //getLineNumber方法用来获取行号
                     
                   }      
                   }
                   catch(IOException  e)
                   {
                            throw  new RuntimeException("读取操作出问题");
                   }
                   finally
                   {
                            try
                            {
                                    if(inr!=null)
                          lnr.close();       
                            }
                           catch(IOException  e2)
                            {
                                     throw   new RuntimeException("lnr.close();出问题了");
                            }
                           
                   }
 
                 
         }
         public static void  soc(Object  obj)
         {
             System.out.println(obj);                           
         }
}

编译运行结果如图1所示:


                            图1



----------- android培训java培训、java学习型技术博客、期待与您交流!------------  




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值