IO流小结之三:流应用的规律、转换流和编码、改变标准输入输出流的方法

              

 学习完IO流操作的基本方法,短时间内会出现很多错觉,不知道遇到问题的时候该用什么流去读,什么流方法去写,这里按照自己的理解来小结一下:

        当涉及IO流操作的时候,我们首先要知道操作的是流对象是字符流还是字节流,按照生存法则,可以先掌握一个万能的方法,那就是通过字节流去读取,因为在IO流中,字节流是万能的,我们知道字符流是基于字节流,只是在字节流的基础上增加了编码,这样我们只要掌握了字节流,就可以对任何IO流进行操作,而对于字符流,只要我们在字节流中增加编码即可搞定下面我们通过需求和程序实现来说明:

        需求:将一个音频文件进行复制

        分析:需要读取的一个源文件是音频文件,必须使用IO字节流的输入流(相当于字符流的读取流)来操作,基于读到的音频文件,复制一个,那么也需要用到字节流的输出流(相当于字符流的写入流);

        所以程序第一步为建立两个流对象,分别是输入流和输出流,因为涉及对文件的操作,所以需要选用File开头的流对象;

                        

FileInputStream fis=new FileInputStream("F:\\IOTest\\m\\传智播客公司介绍.exe")   //读取音频源文件的输入流

                        FileOutputStream fos=new FileOutputStream("F:\\IOTest\\m\\传智播客公司介绍--copy.exe");//复制一个音频源文件的输出流

       有了这个流对象以后,便可以进行文件的读取和复制,在字节流中需要定义一个字节数组来接收文件,,然后通过一个while循环来判断是否读到字节流的末尾,末尾标志位为-1,(在字符流中定义一个字符数组,然后再通过while循环判断数组中的内容是否为空);参考代码如下:

                 byte[]bp=new byte[1024];

int len=0;

long start=System.currentTimeMillis();    //

while((len=fis.read(bp))!=-1){  //判断是否读到文件末尾

fos.write(bp, 0, len);  //按照文件的实际大小进行复制,去掉缓冲数组的无效位;

}

long end=System.currentTimeMillis();

System.out.println(end-start);         //打印出通过FileIputStream和FileOutputStream来进行文件拷贝所耗费的时间;这个时间依赖于处理器的性能;本例拷贝的源文件大小为8231kb,耗时约160毫秒


  因为io流中的reader阻塞式方法,而且fileinputstream方法实际是调用了reader方法,每次读取一位然后存放在数组中,所以为了提高读写效率,通过将fileinputstream方法包装成BufferedStream,因为BufferedInputStream中已经封装了一个缓冲区,默认的缓冲区足够应付一般的应用,代码如下:

 BufferedInputStream Bis=new BufferedInputStream(fis);

BufferedOutputStream Bos=new BufferedOutputStream(fos);

封装之后就可以按照之前的方法进行操作,代码如下:

           byte[]bp=new byte[1024];
int len=0;
long start=System.currentTimeMillis();    //
while((len=Bis.read(bp))!=-1){  //判断是否读到文件末尾

Bos.write(bp, 0, len);  //按照文件的实际大小进行复制,去掉缓冲数组的无效位;
}
long end=System.currentTimeMillis();

System.out.println(end-start);         //通过Buffered包装以后,耗时约40毫秒,由此可见效率

但是: BufferedInputStream也只是在FIleinputstream的基础上通过增减缓冲区来提高效率的,只要我们人为的开辟了一个合适的缓冲区,直接使用FileStream的效率也并不会比 BufferedInputStream差;但是缓冲区技术的引入,作为对基础流的装饰,里面还包含了其他功能增强,例如字符流的BufferedWriter中有一个newline方法,即实现了跨平台的换行符功能;          

         上面介绍了通过字节流复制音频文件的方法,也顺便说明了包装流的效率问题,现在来说如何通过字节流实现字符文件的操作,通用以复制一个字符文件为需求;本文开始已经说到了,字符流其实是在字节流的基础上增加了编码,那么我们使用字节流,然后加入编码是否就可以读写字符文件了呢,这里就不得不用到转换流了;前面一个总结提到了在标准输入的时候,为了使用字符流中的readline方法,而将字节流使用转换流包装为字符流,其实转换流还有一个非常重要的作用就是实现指定编码的读写;

         所以下面隆重介绍两个转换流:

           IputStreamReader      输入转换流  将字节输入流包装为字符流

 OutputStreamWriter    输出转换流  将字符输出流包装为字节流

      例子:

                 需求,实现一个GBK编码的文本的复制,

               分析:文本文件也是字符文件,字符文件就涉及到字符的编码问题,通常默认的系统平台编码是BGK,GBK 是汉字编码标准,全称《汉字内码扩展规范》(GBK),英文名称 Chinese Internal Code Specification ,GBK 向下与 GB 2312 编码兼容,向上支持 ISO 10646.1 国际标准,是前者向后者过渡过程中的一个承上启下的标准。

通过字节流 实现方法:

1、建立一个字节流对象,并传递需要被复制的文件地址;

InputStream is=new FileInputStream("F:\\IOTest\\a\\source.txt");//因为InputStream是FileInputStream的父类,所以可以用父类接收子类,建立输入流对象,这时的输入源是硬盘中的文件。

2、因为涉及对编码的操作,所以必须使用转换流,

InputStreamReader isr=new InputStreamReader(is);//将输入流传递进去,

因为源文件的编码格式是GBK,而系统平台的默认编码也是GBK,所以通过以上操作,即可使用输入转换流中的reader方法进行文件的读取,每次向下读取一个字节,末尾标志位-1;

但是,如果需求改为复制一个编码为UTF-8的字符文件呢,也就是源文件是用的UTF-8编码,而我们的系统环境是用的GBK编码,这样肯定显示就是乱码了,这时我们就需要在转换流中指定编码,代码如下

InputStreamReader isr=new InputStreamReader(is,“UTF-8”);//将输入流传递进去,并增加编码格式,注意编码格式是用的双引号格式。



基于此,我们来看下面一段代码:

FileOutputStream fos=new FileOutputStream("F:\\IOTest\\a\\source.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
osw.write("你好,java\r\n我一定会成功\r\n86571573");
osw.flush();

FileInputStream fir=new  FileInputStream("F:\\IOTest\\a\\source.txt");
InputStreamReader isr=new InputStreamReader(fir,"UTF-8");
BufferedReader bfr=new BufferedReader(isr);
char []bf=new char[1024];
String len=null;
while((len=bfr.readLine())!=null){

System.out.println(len.toUpperCase());
}
 
此段代码实现了通过转换流,写一个UTF-8编码的文件,然后通过转换流读取文件打印。

      接下来我们再看一下转换流在标准输入输出流中的作用;

             1、 键盘输入流:

                     设备:键盘,对应的对象时system.in,键盘输入流应该是字节流,但是操作的又是纯文本文件,为了操作方便,需要转换为字符流,这时候就用到转换流,即InputStreamReader

                   那么实现代码为:

                           IputStreamReader isr=new IputStreamReaderSystem.in);//这里省略了 InputStream is= System.in;

                 需要提高效率,则进一步包装为字符流中的BufferedReader

                           BufferedReader bufr=new BufferedReaderisr);

             2、硬盘输出流

               需求:将键盘录入的信息,存到一个字符文件中,使用UTF-8编码

               设备:硬盘中的一个文件,

               代码:FileWriter fw=new FileWriter“”);

            提高效率,BufferedWriter

         但是FIielWriter是使用的默认编码表GBK 在存储时需要加入指定的编码表时,只能通过转换流才能实现,也就必须使用OutputStreamWriter,而该转换刘对象需要接收一个字节输出流,而且是还可以操作文件的字节输出流,

     OutputStreamWriter oaw=new OutputStreamWriternew Fileoutputstream“demo.txt”),UTF-8);

        同理,对于已知的特殊编码格式的文本,也需要使用转换流InputStreamReader来指定解码标准来读取;( FileWriter FileReader都是指定编码BGK)

         由此可见,字节流和转换流的组合,可以完成IO中的任何操作。只要掌握好了IO流,即可应付所有的IO流应用,但是字符流针对字符文件操作的高效性和便捷性已经成为处理字符流文件的最常用方法,也非常值得我们好好学习。

        最后小结一下 改变标准输入输出流的方式

         System.setInnew FileIputStream “demo.txt”));//改变输入源

        System.setOutnew PrintStream“demo1.txt”));//改变输出源


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值