字节流和字符流基础

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

IO流(字符流)
  用来处理设备之间的数据传输。
  Java对数据的操作时通过流的方式。
  Java用于操作流的对象都在IO包中。
  流按操作的数据分为字节流和字符流,按流向分为输入流和输出流。
  
  数据的最常见体现形式:文件。
  
 1.需求:在硬盘上创建一个文件,并写入一些文件数据。
   找到一个专门操作文件的Writer子类对象:FileWriter。后缀是父类名,前缀是该对象的功能。
   创建一个FileWriter对象,该对象一经创建就必须明确要被操作的文件。
   该文件会被创建到指定的路径下,如果该路径下已有同名文件,将被覆盖
   其实该步就是在明确数据要存放的目的地。
   FileWriter fw = new FileWriter(”f: \\demo.txt“);
   调用write方法,将字符串写入到流中
   Fw.write(”bvdaid“);//在写的时候应注意换行符的使用
   刷新流对象中的缓冲中的数据,将数据刷新到目的地。
   Fw.flush();
   关闭资源,但是关闭前会刷新一次缓冲中的数据,将数据刷新到目的地中。与flush的区别是:flush刷新后流可以继续使用,close刷新后,流将被关闭
   Fw.close();
   
   以上方法都将抛IOException。
   
  2.IO异常的处理方式:
   try{...}
   catch(IOException e){...}
   finally{
   if(fw!=null)
   try{
   Fw.close();
   }
   Catch(IOException e){...}
   如果要关闭的流有多个,应分别关流,而不应在同一个if语句里关。
  
 3.文件的续写:
   传递一个true参数,表示不覆盖已有的文件,而在原文件的末尾处进行续写
   FileWriter fw = new FileWriter(”f: \\demo.txt“,true);
   
 4.文本文件的读取。
   创建一个文件读取对象,和指定的文件相关联
   要保证指定的文件存在,不然会发生FileNotFoundException
   读取文本文件的两种方式:
   Int Read();读取单个字符,返回作为整数读取的字符,读到末尾时返回-1,
   Int read(char[] ch);将数据读到字符数组ch中,返回读到的字符数,如某一次读取到末尾而为读取到数据,返回-1.注意该方法的到的数据转换成字符串时只需将读到的数据进行转换,即用构造方法new String(char[] ch, int offset, int count);
  
 5.字符流缓冲区
  缓冲区的出现提高了对数据的读写效率。
    要结合流才可以使用,对流的功能进行了增强。
  
   1.BufferedWriter
    切记:只要用到缓冲区,就一定要刷新。其实关闭缓冲区,就是在关闭缓冲区中的流对象。所以不用在单独关闭缓冲区所操作的流。
    BufferedWriter提供了一个跨平台的换行符:newLine();
  
  6.BufferedReader
   该缓冲区提高了一个一次读一行的方法readLine,方便于都文本文件的读取;
   当读到文件末尾时,返回null。
  
   readLine原理:无论是读取一个还是多个字符,最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个。
  
   自定义readLine方法:
   Class MyBufferedReader{
   private Reader r;
  public MyBufferedReader(FileReader r){
   this.r = r;
  }
    public String MyReadLine(Reader r) throws IOException{
   //定义一个临时容器,原BufferedReader封装的是字符数组
     StringBuilder sb = new StringBuilder();
     int ch = 0;
   while((ch=r.read())!-1){
    if(ch=='\r')
     continue;
    if(ch=='\n')
     return sb.toString();
    sb.append(ch);
   }
   if(sb.length()!=0)
    return sb.toString();
   return null;
   
    }
  public void close() throws IOException{
   r.close();
  }
   }
 7.装饰设计模式
  当想要对已有的对象进行功能增强时,可以定义一个类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的类称为装饰类。
  装饰类一般会通过构造方法接收备装饰的类,并基于被装饰对象的功能,提供更强大的功能。
  
  自定义装饰类:
  Class MyBufferedReader extends Reader{
    private Reader r;
   public MyBufferedReader(FileReader r){
    this.r = r;
   }
     public String MyReadLine(Reader r) throws IOException{...}
 
   public int read(char[] cbuf,int offset,int len) throws IOException //覆盖父类中的抽象方法
   {
    return r.read(cbuf,offset,len);
   }
   
   public void close() throws IOException //覆盖父类中的抽象方法
   {
    r.close();
   }
 8.LineNumberTeader:可以跟踪行号缓冲区的输入字符流
  LineNumberReader lnr = new LineNumberTeader(new FileReader("..."));
  lnr.setLineNumber();
  String line = null;
  while((line=lnr.readLine())!=null){
   system.out.println(lnr.getLineNumber()+":"+line);  
  }
  lnr.close();
  
  练习:模拟一个带行号的缓冲区对象。
  继承自MyBufferedReader,注意父类方法的使用。
   
IO流(字节流)

 1.available();返回关联文件的大小。利用此方法在定义缓冲区时刻直接定义大小为available的返回值。
  但是该方法要慎用,应为如果操作的文件过大的话会导致内存溢出。
  
 练习:拷贝图片
  1.用字节读取流对象和图片关联
  2.用字节写入流创建一个图片文件
  3.通过循环读写,完成数据的存储
  4.关闭资源
 
 2.字节流缓冲区
  BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("..."));
  BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("..."));
  int by = 0;
  while((by=bfis.read())!=1){
   bfos.write(by);
  }
  bfos.close();
  bfis.close();
  
 3.自定义字节流缓冲区。
  缓冲区原理:缓冲区read方法的原理是先用被装饰类的read(buf)方法将一批目标数据读到一个数组,
 然后再从数组里一个一个字节读出来
  既然如此,那么可以定义一个字节数组,用一个计数器count记录读到数组中的字节数,当数组中的字节数被取出一个时,count的值-1,
 当减到0时,再从源文件读取到到数组中,如果read(buf)的值为-1,表示源文件已读取完毕。
  同时用一个指针记录取出数组中元素的数组元素,取出一个后,指针+1,当指针为arr.length-1时,表示数组中的元素已取完,再次读取源文件。
  
  class MyBufferedInputStream{
   private InputStream in;
   ptivate byte[] buf = new byte[1024];
   private int count = 0,pos = 0;
   public MyBufferedInputStream(InputStream in) {
    this.in = in;
   }
   
   public int myRead(){
    if(count==0){
     count = in.read(buf);
     if(count<0)
      return -1;
     pos = 0;
     
     byte b = buf[pos];
     count--;
     pos++;
     
     return b&255;//如果读到的第一个字节是11111111(-1),那么类型提升为int后会在高位补-1,则仍为-1;
         //那么就会不再读取了。那么只要在高位补0,既可以保证数据的原样性,又可以避免出现-1.
        
    }
    else{
     byte b = buf[pos];
     count--;
     pos++;
     return b&&0xff;
    }
    return -1;
    
   }
   public void close(){
    in.close();
   }
  }
  
 4.读取键盘录入
  InputStream in = System.in;
  StringBuilder sb = new StringBuilder();
  while(true){
   int ch = in.read();
   if(ch=='\r')
    continue;
   if(ch=='\n'){
    String s = sb.toString();
    if("over".equals(s))
     break;
    
    System.out.println(s.toUpperCase());
    sb.delete(0,sb.length()); //清空用delete。但是清空集合用clear
   }
   sb.append((char)ch);
   
  }
 
 5.转换流扩展
  想要把录入的数据按指定编码表(utf-8),将数据存储到文件中。
  目的:OutputStream Writer
  是否纯文本?是:Writer
  设备:硬盘,文件 FileWriter
  但是FileWriter使用的是默认编码表GBK。
  
  要想加入指定编码表,只能使用转换流。OutputStreamWriter.
  而转换流需要操作字节输出流,还可以操作文本文件,可传入FileOutputStream
  
  下面是需要高效率和编码表的转换流用法:
  BufferedWriter bufw =
   new BufferedWriter(new OutputStreamWriter(new FileOutputStream("..."),"utf-8"));
  
  什么时候使用转换流?字节流和字符流之间的桥梁,通常需要用到编码转换时,需要用转换流。
 
 6.异常日志信息
  1.改变标准输出,将异常信息存储在文件中
  System.setOut(new PrintStream("exception.log"));
  e.printStackTrace(System.out);
  
  2.帮助完成日志信息建立的包:log4j
  
 7.系统信息
  Properties prop = System.getProperty();
  prop.list(new PrintStream("...")); //注意list方法与File对象中list的区别

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值