黑马程序员_字节流

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

字节流:

 需求:想要操作图片数据。这时就要用到字节流
 基类:InputputStream  OutputStram
 类名中带有stream的流都是字节流
 底层有缓冲区


一:比较字符流与字节流中的write方法
   字符流中:FileWriter fw=new FileWriter("demo.txt");
    fw.write("abcde");
             fw.flush();   
             //经过这三步才能将要写的数据写到目的地
   字节流中:FileOutputStream fos=new FileOutputStream("fos.txt");
    fos.write("abcde".getBytes());  
             //有这两步就可以,无需刷新  


二:字节流的两种读方法
 1.读一个写一个,边读边写
   public static void readFile_1() throws IOException
{
    FileInputStream fis=new FileInputStream("fos.txt");
    int ch=0;
    while((ch=fis.read())!=-1)
    {
System.out.print((char)ch);
    }
    fis.close();

 2.先读到字节数组中,再写
   public static void readFile_2() throws IOException
{
    FileInputStream fis=new FileInputStream("fos.txt");
    byte [] buf=new byte[1024];
    int len=0;
    while((len=fis.read(buf))!=-1)
    {
System.out.print(new String(buf,0,len));
    }
        } 
 3.int num=fis.available();  //available方法放回文件中的字符个数
   byte [] buf=new byte[fis.available()];
   fis.read(buf);
   //定义一个刚好合适的缓冲区,不用再循环了。
     这种方法虽然方便快捷,但有危险,数组的容量不能太大了,否则,内存很有可能因为
     溢出,受不了而废掉。它只适用于操作数据较小的文件。  


三:复制一个图片
   思路:
 1.用字节读取流对象和图片关联。
 2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
 3.通过循环读写,完成数据的存储
 4.关闭资源
 eg:FileOutputStream fos=null;
     FileInputStream fis=null;
     try
     {
fos=new FileOutputStream("复制的图片.bmp");
fis=new FileInputStream("..\\media\\84.bmp");
byte [] buf=new byte[1024];
int len=0;
while((len=fis.read(buf))!=-1)
{
   fos.write(buf,0,len);
}
     }
     catch (IOException e)
     {
throw new RuntimeException("复制文件失败");
     }
     finally{}


四:通过缓冲区复制一首MP3歌曲
 eg:public static void main(String[] args) throws IOException
{
           long start=System.currentTimeMillis();
           copy_1();
  long end=System.currentTimeMillis();
           System.out.println((end-start)+"毫秒");
}
     BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("..\\media\\
     刘若英 - 当爱在靠近.mp3"));
     BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("复制的歌.mp3"));
     int by=0;
     while((by=bufis.read())!=-1)
     {
bufos.write(by);
     }
     bufos.close();
     bufis.close();


五:通过自制的缓冲区来复制一首歌
    eg:public static void copy_2() throws IOException
{
  MyBufferedInputStream bufis=new MyBufferedInputStream(new FileInputStream                     ("..\\media\\刘若英 - 当爱在靠近.mp3"));
           BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("复制的              歌.mp3"));
           int by=0;
  System.out.println("第一个字节:"+bufis.myRead());
  while((by=bufis.myRead())!=-1)
           {
     bufos.write(by);
  }
  bufos.close();
  bufis.myClose();
}
        class  MyBufferedInputStream
        {
  private InputStream in;
  private byte [] buf=new byte[1024];
  private int pos=0,count=0;
  MyBufferedInputStream(InputStream in)
  {
this.in=in;
  }
           //一次读一个字节,从缓冲区(字节数组)获取
  public int myRead() 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; //注意:该处的b为用二进制格式存储歌曲数据的字节数组
}
else if(count>0)
{
  byte b=buf[pos];
  count--;
  pos++;
  return b&0xff; //此处的b和原来一样
}
  return -1;
    }
   public void myClose() throws IOException
   {
in.close();
   }
         }


六:注:五中的b从二进制变为int形式时有一个小技巧:
    b返回时为二进制,默认为8位,int型占四个字节,java中二进制表示为32位
    由返回的二进制b值转化为int型,系统默认b不足32位时,在它前面补1;即转化为int
    型后,返回的值变成了负数,而
    while((by=bufis.myRead())!=-1)
    {
bufos.write(by);
    }
    不满足循环的条件,即一开始就不能写任何数据到指定的目的地,也就是一点内容都没有
    复制,所以运行后生成的文件为空文件。
    要想使返回的二进制b值转化为int型时不改变其值,又让其变为十进制整数
    方法是:保留n位,与2的n次方减1相与
    eg:
    byte:-1 ---》int :-1;
    11111111      11111111 11111111 11111111 11111111
    11111111 11111111 11111111 11111111
   &00000000 00000000 00000000 11111111
   -------------------------------------
    00000000 00000000 00000000 11111111
    为什么返回时要为int型呢? 原因是避免了返回-1及负数的情况,导致不满足写的条件,从而不能进行        写操作,将byte型转为int型后,字节数增大了,一个变为了四个,按道理write的目的地应增大4倍。但
    write方法是只写有效的低字节位数据,即它一直在做强转的动作,将32位只保留低8位有效位的强转。


七:读取键盘录入
 1.System.out:对应的是标准的输出设备:控制台
 2.System.in:对应的标准输入设备:键盘


   需求:
   通过键盘录入数据
   当录入一行数据后,就将改行数据进行打印
   如果录入的数据时over,那么停止录入
   eg:public static void main(String[] args) throws IOException
{
  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()); 
                   //toUpperCase():使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
  sb.delete(0,sb.length()); 
                   //清空该字符串缓冲区对象b中的数据,起到刷新的效果

else 
                {
  sb.append((char)ch);
}
  } 
        }


八:字节流转换为字符流的桥梁
 1.InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。     它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 
   每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启     用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节  2.为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。
 eg: InputStream in=System.in;  
      BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
 3.七中的代码类似读一行数据的原理。也就是readLine方法
   readLine方法是字符流bufferedReader类中的方法。
   而键盘录入的read方法是字节流InputStream的方法
   这就需要将字节流转换为字符流,再使用readLine方法
   eg:
   import java.io.*;
   class  TransStreamDemo
   {
public static void main(String[] args) throws IOException
{
//获取键盘录入对象
1.InputStream in=System.in;
//将字节流对象转换为字符流对象。使用转换流:BufferedReader
                2.InputStreamReader isr=new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区高效操作,使用BufferedReader
3.BufferedReader bufr=new BufferedReader(isr);


                //键盘录入最常见的写法,System.in一次只能写一个字符,而上面的写法却能一次读入
 一行字符,效率很高。
4.OutputStream out=System.out;
5.OutputStreamWriter osw=new OutputStreamWriter(out);
6.BufferedWriter bufw=new BufferedWriter(osw);


String line=null;
while((line=bufr.readLine())!=null)
{
     if("over".equals(line))
    break;
   //System.out.println(line.toUpperCase());
                      7.bufw.write(line.toUpperCase());
     8.bufw.newLine();
     9.bufw.flush();                       
}
bufr.close();
}
   }
   输出底层用的就是流装置,可以用流来改写System.out.println();
   上面的代码中的123和789六行代码就是用来改写它的。
   其中:123句等价为:BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
         456句等价为:BufferedWriter bufr=new BufferedWriter(new OutputStreamWriter(System.out));      
九:字符流转换为字节流的桥梁
 1.OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字      节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
   每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得     到的这些字节将在缓冲区中累积。可以指定此缓冲区的大小,不过,默认的缓冲区对多数用途来说已足够      大。注意,传递给 write() 方法的字符没有缓冲。 
 2.为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中
  eg: Writer out= new BufferedWriter(new OutputStreamWriter(System.out));
 
十:确定具体程序该使用字符流还是字节流的方法
  流操作的基本规律:
  通过两个明确来完成。
  1.明确源和目的
    源:输入流:InputStream Reader
    目的:输出流:OutputStream Writer
  2.明确操作的数据是否是纯文本
    是:字符流
    不是:字节流


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


  分情况:
  情况一:想把键盘录入的数据存储打印到控制台
      源:键盘
    目的:控制台
  情况二:想把键盘录入的数据存储到一个文件中
      源:键盘
    目的:文件
  情况三:需求:想要将一个文件的数据打印到控制台上
      源:文件
    目的:控制台


十一:实例
 1.将一个文本中的数据存储到另一个文件中,复制文件。
    源:因为是源,所以使用读取流:InputStream Reader
是不是操作文本文件。
是!这是就可以选择Reader
这样体系就明确了


接下来明确要使用该体系中的那个对象。
明确设备:硬盘上一个文件。
Peader体系中可以操作文件的对象是FileReader


        是否需要提高效率
是!.加入Readter体系中的缓冲区BufferedReader.


FileReader fr=new FileReader("a.txt");
        BufferedReader bufr=new BufferedReader(fr); 


  目的:OutputStream Writer
是否是纯文本。
是!Writer。
设备:硬盘,一个文件
Write体系中可以操作文件的对象FileWriter。
是否需要提高效率
是!.加入Readter体系中的缓冲区BufferedReader.
 
        FileWriter fw=new FileWriter(b.txt);
BufferedWriter bufw=new BufferdWriter(fw); 
 ------------------------------------------------------------------------------
  2.   需求:将键盘录入的数据保存到一个文件中。
       这个文件有源和目的都存在。      
       源:InputStream Reader
  是不是纯文本?是!Reader


       设备:键盘:对应的对象是System.in
    不是选择Reader吗?System.in对应的不是字节流吗?
             为了操作键盘的文件数据方便。转成字符流按照字符串操作是最方便的
             所以既然明确了Reader,那么就将System.in转换成Reader
             用了Reader体系中转换流:InputStreamReader


             InputStreamReader isr=new InputStreamReader(System.in);


             需要提高效率吗?需要!BufferedReader
             BufferedReader bufr=new BufferedReader(isr);


       目的:OutputStram Writer
             是否是纯文本?是!writer
       设备:硬盘。一个文件。使用FileWriter
             FileWriter fw=new FileWriter(c.txt);
             需要提高效率吗?需要
             BufferedWriter bufw=new BufferedWriter(fw);
-----------------------------------------------------------------------------
扩展:想要把录入的数据按照指定的编码表,将数据存储到文件中    
       目的:OutputStram Writer
             是否是纯文本?是!writer
       设备:硬盘。一个文件。使用FileWriter
             但是FileWriter是使用的默认编码表:GBK
    
             但是存储时,需要加入指定的编码表,而指定的编码表只有转换流可以指定
    所以要使用的对象是OutputStreamWriter
    而该转换流对象要接收一个字节流,而且还可以操作文件的字节输出流,用FilOutputStream

    OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(d.txt),"UTF-8");
             需要提高效率吗?需要
    BufferedWriter bufw=new BufferedWriter(osw);
-----------------------------------------------------------------------------
       记住:转换流什么时候实用,字符和字节之间的桥梁,通常涉及到字符编码转换时,
       需要用到转换流
       转换流的由来:就是因为它能指定编码,他能把字节转换过来加指定的码表。


十二:改变默认的输入源设备和输出目的设备
  eg:        
     System.setIn(new FileInputStream("PersonDemo.java"));
     //这一句改变的是输入源设备,改为文件
     System.setOut(new PrintStream("zz.txt"));

     //这一句改变的是输出流设备,改为文件


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值