黑马程序员_IO(1) 字节流&字符流

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

一.字节流

字节流的两个基类是InputStream和OutputStream,相应的缓冲区是BufferedInputStream和BufferedOutputStream
处理非字符的数据,图片,音频,视频等,采用字节流读写操作
字节流的写操作,不用刷新处理,与底层交互处理,而且不涉及编码问题
字节流特有的读取方式: available() 方法返回文件所有字节数
eg: 文件字节流读写操作
import java.io.*;
class  FileStreamDemo
{
    publicstaticvoid main(String[]args) throws IOException
    {
//     writeFile();
       readFile_3();
    }
    //第三种d读取方式:字节流特有的读取方式,使用available()方法。
    publicstaticvoid readFile_3() throws IOException
    {
       FileInputStream fis = new FileInputStream("fos.txt") ;
       //int num = fis.available();
       byte [] buf =newbyte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了。
       fis.read(buf);
       System.out.println(new String(buf));
       fis.close();
    }
    //第二种读取方式:利用字符数组作为缓冲区,读取。
    publicstaticvoid readFile_2() throws IOException
    {
       FileInputStream fis = new FileInputStream("fos.txt") ;
       byte[] buf = newbyte[1024];
       int len = 0;
       while((len =fis.read(buf))!=- 1)
       {
           System.out.println(new String(buf,0,len));
       }
       fis.close();
    }
    //第一种读取方式:一个字节一个字节的读取。
    publicstaticvoid readFile_1() throws IOException
    {
       FileInputStream fis = new FileInputStream("fos.txt") ;
       int ch = 0;
       while((ch = fis.read())!=- 1)
       {
           System.out.println((char)ch);
       }
       fis.close();
    }
    publicstaticvoid writeFile() throws IOException
    {
       FileOutputStream fos =new FileOutputStream("fos.txt");
       fos.write("aabcde中国你好吗".getBytes());
       //与字符流Writer相比,没有flush
       fos.close();
    }
}

eg:复制图片
import java.io.*;
class CopyPicDemo 
{
    publicstaticvoid main(String[]args)
    {
       copyPic("pic.jpg","D:\\pic.jpg");

    }
    publicstaticvoid copyPic(Stringsour,String des) 
    {
       FileInputStream fis = null;
       FileOutputStream fos = null;
       try
       {
           fis = newFileInputStream(sour);
           fos = newFileOutputStream(des);
           byte[] buf = newbyte[1024];
           int len = 0;
           while((len =fis.read(buf))!=-1)
           {
              fos.write(buf,0,len);
           }
       }
       catch (IOException e)
        {
           thrownewRuntimeException("复制文件失败");
       }
       finally
       {
           try
           {
              if(fis!=null)
                  fis.close();
           }
           catch (IOException e)
           {
              thrownewRuntimeException("读取关闭失败");
           }
           finally
           {
              try
              {
                  if(fos!=null)
                     fos.close();
              }
              catch (IOException e)
              {
                  thrownewRuntimeException("写入关闭失败");
              }
           }          
       }
    }
}

eg:复制MP3文件


注意几点: 读取一个字节8bit都是1,最高位为1,出现负数情况 如 -1,int类型提升仍然是负数 -1,导致数据位读取不完整
          解决思路:保留低8bit,舍弃高位24bit,字节类型位运算 & 255 得到的值作为read方法返回值;
自定义字节缓冲区
import java.io.*;
class MyBufferedInputStream
{
   private InputStream in;
   private byte[] buf= new byte[1024*4];
   privateintpos= 0,count= 0;
   public MyBufferedInputStream(InputStream in )
   {
      this.in = in;
   }
   //一次读一个字节,从缓冲区(字节数组)获取
   publicintmyRead() throws IOException
   {
      //通过in对象读取到硬盘上的数据,并存储buf中。
      if(count == 0)
      {
         count = in.read(buf);
         if(count<0)
            return -1;
         pos = 0;
         byte b = buf[pos];
         count--;
         pos++;
         return b&255;
      }
      else if(count>0)
      {
         byte b = buf[pos];
         count--;
         pos++;
         return b&0xff;//0xff即是16位进制的255
      }
      return -1;
   }
   public void myClose() throws IOException
   {
      in.close();
   }
}

复制MP3文件
eg:
import java.io.*;
class CopyMp3 
{
   publicstaticvoidmain(String[] args) throws IOException
   { 
      long start = System.currentTimeMillis();
      copy_2();
      long end = System.currentTimeMillis();
      System.out.println((end-start)+"毫秒");
   }
   //通过自定义的字节流缓冲区完成复制。
   public static void copy_2() throws IOException
   {
      MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("a.mp3"));
      BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("a.mp3"));
      int by = 0;
      //System.out.println("第一个字节是:"+bufis.myRead());//结果为-1。
      int len = 0;
      while((len = bufis.myRead())!= -1)、
      {
         bufos.write(len);//write其实在做一个强转动作
         //bufos.flush();//这里不要写flush,否则复制速度会大幅降低。
         //System.out.println(len); 
      }
      bufis.myClose();
      bufos.close();
   }
   //通过字节流的缓冲区完成复制。
   public static void copy_1() throws IOException
   {
      BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("a.mp3"));
      BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("b.mp3"));
      int len = 0;
      while((len = bufis.read())!= -1)
      {
         bufos.write(len);
      }
      bufis.close();
      bufos.close();
   }
}

读取键盘录入数据
eg:
/*
读取键盘录入。
System.out:对应的是标准输出设备,控制台。
System.in:对应的是标准的输入设备,键盘。
通过键盘录入数据。
当录入一行数据后,就将改行数据打印。
如果录入的数据是over,那么停止录入
*/
import java.io.*;
import java.util.*;
class  ReadIn
{
    publicstaticvoid main(String[]args) throws IOException
    {
       InputStream in = System.in;
       StringBuilder sb = new StringBuilder();
       while(true)
       {
           int by = in.read();
           /*
            read()是一个阻塞式的方法,它每次读取一个字节,如果没有数据,它会一直等待。
            1.磁盘文件有结束标记
            2.在DOS控制台 读取\r\n 结束
            3.windows中,敲回车键,就是加入换行符,而windows中的换行符是用\r\n两个字符表示的,这时会有3个。
            */        
           if(by=='\r')             
              continue;                   
           if(by=='\n')
           {   
              String s =sb.toString();
              if("over".equals(s))
                  break;
              System.out.println(s.toUpperCase());
              //这里sb缓冲区必须清空,否则会导致两个结果:1,会被上次敲入的字符又打印一遍;2、导致结束标记失效。
              sb.delete(0,sb.length());
                  //continue;
           }
           else       
              sb.append((char)by); 
       }      
    }
}

流转换
InputStreamReader  , OutputStreamWriter
import java.io.*;
class TransStreamDemo 
{
    publicstaticvoid main(String[]args) throws IOException
    {
    /*  //获取键盘录入对象
       InputStream in = System.in;
       //将字节流转成字符流对象,通过InputstreamReader
       InputStreamReader is = newInputStreamReader(in);
       //为提高效率,采用BufferedReader。
       BufferedReader bufr =new BufferedReader(is);
*/
       //键盘输入最常见的写法
       BufferedReader bufr = 
       new BufferedReader(new InputStreamReader(System.in));
       BufferedWriter bufw = 
       new BufferedWriter(new OutputStreamWriter(System.out));
       String line =null;
       while((line =bufr.readLine())!=null)
       {
           if(line.equals("over"))
              break;
           bufw.write(line.toUpperCase());
           bufw.newLine();//这个跨平台
           bufw.flush();
       }
       bufw.close();
       bufr.close();
    }
}
流操作规律:

1.      明确源和目的。
源:输入流,InputStream和Reader;
目的:输出流,OutputStream和Writer

2.      明确操作的数据是否是纯文本。
是:字符流
不是:字节流。

3.      当体系明确后,再明确要使用哪个具体的对象。
通过设备来区分:
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台

System类 流重定向  setIn()、setOut()、setError()方法
异常信息化
eg:
import java.io.*;
import  java.util.*;
import java.text.*;
class ExceptionInfo 
{
    publicstaticvoid main(String[]args) throws IOException
    {
       try
       {
           int [] arr = newint[2];
           System.out.println(arr[3]);
       }
       catch (Exception e)
       {
           try
           {
              Date d= new Date();
              SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-DDHH:mm:ss");
              Strings =sdf.format(d);
              PrintStream ps = new PrintStream(new FileOutputStream("exception.log",true));
              ps.println(s);
              System.setOut(ps);
           }
           catch (IOException ex)
           {
              thrownewRuntimeException("日志文件创建失败");
           }
           e.printStackTrace(System.out);
       }
    }
}
/*
log4j 日志工具包操作
*/

二.字符流

|-----------Writer

    |----OutputStreamWriter:字符流通向字节流的桥梁,可以指定编码。

    |--FileWriter:文件写入流,会创建一个文件,通过构造函数定义是续写还是覆盖。

    |----BufferedWriter:字符写入流,定义了缓冲区,可以提高效率;缓冲区为字符数组,可定义缓冲区大小,默认缓冲区大小为8k

eg:

package bxd.day18;
import java.io.*;
class FileWriterDemo3
{
    publicstaticvoid main(String[] args)
    {
        FileWriterfw = null;//这句要定义在异常处理外部,提升其作用域,否则在finally中读不到fw。
        try
        {
            //文件续写:传递一个true参数,代表不覆盖一个已有的文件,并在已有文件的末尾处进行数据的续写。
            fw= newFileWriter("demo.txt",true);
            fw.write("nihao\r\nxiexie");           
            //刷新流对象中的缓冲中的数据。将数据从内存中刷到目的地中。
            fw.flush();         
        }
        catch (IOException e)
        {
            System.out.println(e.toString());
        }
        finally
        {
            try
            {
                //这里必须判断一下,因为如果fw的初始化没有成功,会抛出空指针异常。这里的fw操作是针对fw.write()方法抛出异常后进行的处理。

                if(fw!=null)

                    //IO底层调用了系统的资源,IO流建立成功使用结束时,一定要释放资源。fw.close()之前,会先调用flush方法,

                    //这两个方法的区别是::flush刷新后,流可以继续使用;close刷新后,会将流关闭,若再次使用流会抛出异常。

                    //注意:如果没有调用flush也没用调用close方法,那么磁盘文件中看不到写入效果。                

                    fw.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString());
            }
        }       
    }
}

|-----------Reader

      |----InputStreamReader:字节流通向字符流的桥梁,可以指定编码。

      |--FileReader:文件读取流,文件需存在,否则抛出异常。      

      |----BufferedReader:字符读取流,定义了缓冲区,可以提高效率;缓冲区为字符数组,可定义缓冲区大小,默认缓冲区大小为8k

eg:

/*
第一种读取方式:一个字符一个字符的读取
*/

import java.io.*;
import static java.lang.System.*;
class FileReaderDemo
{
   publicstaticvoid main(String[] args)throws IOException
   {
      //创建一个文件读取流对象,和指定名称的文件相关联。
      //要保证该文件是已经存在的,如果不存在,会发生异常:FileNotFoundException。
      FileReaderfr = newFileReader("demo.txt");
      int ch =0;
      while((ch=fr.read())!=-1)
      {
         out.println((char)ch);
      }
      fr.close();
   }

}


eg: 字符数组读取
/*
第二种读取方式:通过字符数组进行读取。
*/
import java.io.*;
import staticjava.lang.System.*;
class FileReaderDemo2
{
   publicstaticvoid main(String[] args)throws IOException
   {
      FileReader fr = new FileReader("demo.txt");
      //定义一个字符数组(也可称为缓冲区),用于存储读到的字符。
      //该reader(char[])返回的值是读到的字符个数。
      char [] buf =new char[1024];//通常情况下数组的长度会定义为1024的整数倍
      int num =0;
      while((num=fr.read(buf))!=-1)
      {
         out.println("num="+num+"...."+new String(buf,0,num));
         //为什么不用new String(num),因为如果最后一次读取的个数如果不满足1024个,那么会把上次取出而本次没有覆盖掉的字符也打印出来。
      }
      fr.close();
   }
}

文件复制:

/*
将c盘的一个文本文件复制到D盘。
复制原理:
其实就是C盘下的文件数据存储到D盘的一个文件中。
步骤:
1.在D盘创建衣蛾文件,用于存储C盘文件中的数据。
2.定义读取流和C盘文件关联。
3.通过不断的读写完成数据存储。
4.关闭资源。
*/
import java.io.*;
class CopyTest
{
   publicstaticvoid main(String[] args)throws IOException
   {     
      //copy_1();
      copy_2();
   }
   public staticvoidmyCopy(String sour,String dest)throws IOException
   {
      FileReader fr = newFileReader(sour);
      FileWriter fw = newFileWriter(dest);
      char[] buf =newchar[1024];
      int num =0;
      while((num =fr.read(buf))!=-1)
      {
         fw.write(buf,0,num);       
      }
      fr.close();
      fw.close();
   }
   public static void copy_2()
   {
      FileWriterfw = null;
      FileReaderfr = null;
      try
      {
         fw= new FileWriter("d:\\a.txt");
         fr= new FileReader("e:\\a.txt");
         char [] buf =newchar[1024];
         int len =0;
         while((len=fr.read(buf))!=-1)
         {
            fw.write(buf,0,len);
            //其实fw里也有一个缓冲区,用于存放要写的内容,当缓冲区满了,自动调用底层方法,写入文件中。
         }
      }
      catch (IOException e )
      {
         thrownew RuntimeException("读写失败");
      }
      finally
      {
         if(fr!=null)
            try
            {
                fr.close();
            }
            catch (IOException e )
            {
            }
         if(fw!=null)
            try
            {
                fw.close();             
            }
            catch (IOException e )
            {
            }
      }
/*
      finally
      {        
         try
         {
            if(fr!=null)
            fr.close();
         }
         catch(IOException e )
         {
         }
         finally
         {
            try
            {
                if(fw!=null)
                fw.close();             
            }
            catch(IOException e )
            {
            }
         }
      }
*/   
   }
   publicstaticvoid copy_1()throws IOException
   {
  
      FileReaderfr = newFileReader("b:\\a.txt");
      int ch =0;
      while((ch = fr.read())!=-1)
      {
         fw.write(ch);
      }
      fw.close();
      fr.close();
   }
}

字符缓冲区

eg

import java.io.*;
class BufferedWriterDemo
{
   publicstaticvoid main(String[] args)throws IOException
   {
      //创建一个字符续写入流对象。
      FileWriter fw = newFileWriter("buf.txt",true);
      //为了提高字符写入效率,加入了缓冲技术。
      //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
      BufferedWriter bufw = new BufferedWriter(fw);//原理是这个对象里边封装了数组。
      for(int x = 1 ;x < 5; x++)
      {
         bufw.write("abcde"+x);
         bufw.newLine();
         bufw.flush();
      }
      //记住,只要用到缓冲器,就要记得 刷新。
      //bufw.flush();
      //其实关闭缓冲区,就是在关闭缓冲区中的流对象。
      bufw.close();
   }
}
eg:

import java.io.*;
class BufferedReaderDemo
{
   publicstaticvoid main(String[] args)throws IOException
   {
      //创建一个读取流对象和文件想关联。
      FileReaderfr = newFileReader("buf.txt");
      //为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数。
      //默认的缓冲区char[]数组大小为8k。
      BufferedReaderbufr = newBufferedReader(fr);
      Stringline = null;
      while((line=bufr.readLine())!=null)
      {
         System.out.println(line);
      }
      bufr.close();
   }
}
利用缓冲区拷贝文件

eg:

/*
通过缓冲区复制一个.java文件。
*/
import java.io.*;
class CopyTextByBuf
{
   publicstaticvoid main(String[] args)//throws IOException
   {
      BufferedReaderbufr = null;//如果不先定义为空,finally中就无法访问读写缓冲区的引用
      BufferedWriterbufw = null;
      try
      {
         bufr= new BufferedReader(newFileReader("BufferedReaderDemo.java"));
         bufw= new BufferedWriter(newFileWriter("B:\\BufferedReaderDemo.java"));
         Stringline = null;//line此时即是中转站       
         while((line =bufr.readLine())!=null)
         {//readLine只返回该行的有效内容,并不返回换行符,所以写入的试试,要加换行符或调用newLine方法。
            bufw.write(line);
            bufw.newLine();
            bufw.flush();
         }        
      }
      catch (IOException e)
      {
         thrownew RuntimeException("读写失败");
      }
      finally
      {        
         try
         {
            if(bufr!=null)
                bufr.close();
         }
         catch (IOException e)
         {
            thrownew RuntimeException("读取关闭失败");
         }     
         try
         {
            if(bufw!=null)
               bufw.close();
         }
         catch (IOException e )
         {
            thrownew RuntimeException("写入关闭失败");
         }
      }
   }
}


LineNumberReader

LineNumberReader也是一个包装类,它在BufferedReader的基础上增加了一个记录行号的功能,而记录行号是在readLine方法中操作的,所以它继承了BufferedReader并复写了readLine方法,同时增加了getLineNumbersetLineNumber方法。

eg:

import java.io.*;
class LineNumberReaderDemo
{
    publicstaticvoid main(String[] args)throws IOException
    {
       FileReader fr = new FileReader("PersonDemo.java");
       LineNumberReader lnr = new LineNumberReader(fr);
       String line = null;
       lnr.setLineNumber(100);
       while((line=lnr.readLine())!=null)
       {
          System.out.println(lnr.getLineNumber());
       }      
       lnr.close();
    }
}
















------- android培训java培训、期待与您交流! ----------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值