黑马程序员——Java基础——字节流文件操作、键盘录入、转换流、流操作规律、异常日志等

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ----------

一、字节流File读写操作

   1、概述

      字节流常用于操作其他媒体文件。

   2、由于媒体文件数据中都是以字节存储的,所以,字节流对象可直接对媒体文件的数据写入到文件中,而可以不用再进行刷流动作。

   3、读写字节流:InputStream   输入流  OutputStream  输出流

   4、为何不用进行刷流动作:

        字符流其实一样用的字节,但是它需要把字节临时存起来,一个中文两个字节,读一个字节后,不能立刻操作,所以,读完一个字节,再读一个字节,查表去,查完表,才能进行操作,所以需要刷新动作。

而如果直接使用字节流,没有具体缓冲区,就是不管什么数据,我都以字节来操作,读一个字节,操作一次,所以它可以直接把字节写到目录里面,所以它是不需要刷新的。

到了缓冲区的时候,才到了刷新机制。

   5InputStream特有方法:

        int available();   返回文件中的字节个数

可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。

   6、三种方式读取数据

     1)一个一个读

     2)用字节数组缓冲   Byte[]buf=new byte[1024];

     3int available()   返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数

  哪一种好呢?

思考一个问题:

字节流是操作图片或声音等数据的,现在有一个电影文件,大约有1GB。也就是说available()返回的数值会很大,内存如果还没有1GB,用第三种的话,内存是不就爆了。内存溢出

所以,第三种方法要慎用,如果数据过大,还是以第二种为主。

   7、  练习   复制一个图片

 

 

  

8、自定义字节流缓冲区

根据字节流缓冲区的原理,自定义一个字节流缓冲区。

注意:字节流的读一个字节的read方法为什么返回值类型不是byte,而是int。因为有可能会读到连续8个二进制1的情况,8个二进制1对应的十进制是-1.那么就会出现数据还没有读完已经结束的情况。因为我们判断读取结束是通过结尾标记-1来确定的。

 所以,为了避免这种情况将读到的字节进行int类型的提升。并在保留原字节数据的情况前面了补了240,变成了int类型的数值。而在写入数据时,只写该int类型数据的最低8位。

  byte类型的-1提升为int类型时还是-1。原因:因为在81前面补的全是1导致的。如果在81前面补0,即可以保留原字节数据不变,又可以避免-1的出现。这时将byte型数据&255即可。

   练习 MP3文件的复制

  练习:自己定义一个字节流的缓冲区来复制MP3文件。

   图

 

 

二、IO流——读取键盘录入

      需求:读取键盘录入。之前我们输入流中都是文件的数据,是硬盘中的数据,现在我们的数据源变了,我们想从键盘获取数据。

   1、概述

         System.out:对应的是标准的输出设备,屏幕或者控制台

         System.in:对应的是标准的输入设备,默认是键盘。

打开System.in,    public static final  InputStream in ,发现正是字节读取流。 

   2、关于录入一行数据的问题

      需求:通过键盘录入数据

当录入一行数据后,就将该行数据打印。如果录入的数据是over,那么停止录入。

 
 
import java.io.*;
class Readin
{
public static void Main(String[]args) throws IOException
{
InputStream in=system.in;
//关键是循环停止的条件是什么呢?只要是键盘录入,只有按ctrl+c才能停止,而ctrl+c就是往程序插入一个结束标记。而且我们是想录入一行数据再打印。
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());//清空缓冲区的作用
}
else
sb.append((char)ch);
}
}
}

 

 这个代码似曾相识,因为readline方法就是如此实现的。

问题:

ReadLine方法是字符流BufferedReader类中的方法

而键盘录入的read方法是字节流InputStream的方法

解决方法:转换流

三、转换流

1)概述

 public class InputStreamReader  extends  Reader 

  InputStreamReader 是字节流通向字符流的桥梁:

它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

2)字节流转换字符流操作步骤

          A   获取键盘录入对象

          B 将字节流对象转成字符流对象,使用转换流:InputStreamReader

                InputStreamReader isr=new InputStreamReader(in);

          C为了提高效率,将字符流进行缓冲区技术的高效操作,使用BufferedReader

                BufferedReader bufr=new BufferedReader(isr);

 故此,键盘录入固定简化格式变为:

           BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

4、练习

   

   3) OutputStreamWriter字符流转换字节流

     录入的是字符数据,存到硬盘上的是字节数据。步骤和InputStreamReader转换流一样。

      public  class  OutputStreamWriter   extends   Writer

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。

为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器。

常用形式:

 Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

 

 

 

四、流操作规律

只要我们明确了我们操作流的源和目的,以及明确所操作数据的性质,是纯文本还是字节数据,是否需要提高效率等,就可以轻而易举完成流操作。

1、源是键盘录入

   目的是控制台

2、需求:想把键盘录入的数据存储到一个文件中。

   源:键盘

   目的  文件

  使用字节流转换字符流的转换流:InputStreamReader

3、需求:想要将一个文件的数据打印在控制台上

   源:文件

   目的:控制台

  使用字符流转换为字节流的转换流:OutputStreamWriter

4、流操作的基本规律:

          通过三个明确来完成

         1) 明确源和目的

            源:  输入流  InputStream  Reader

           目的:输出流  OutputStream  Writer     

         2) 明确操作的数据是否是纯文本。

             是:字符流

            不是 :字节流

        3) 当体系明确后,再明确要使用具体哪个对象

            通过设备来进行区分

            源设备有:内存、硬盘、 键盘

            目的设备:内存,硬盘,控制台

5、举例说明

     5.1 第一个需求:将一个文本文件中的数据存储到另一个文件。复制文件

         1)源:因为是源,所以使用读取流 InputStream   Reader

            是不是操作文本文件?   是:选择Reader

           这样,体系就明确了。 接下来,明确要使用该体系中的哪个对象。

           明确设备:硬盘的文件

           Reader体系中可以操作文件的FileReader

        2) 目的:OutputStream Writer

           是否是纯文本? 是 Writer

           设备:硬盘的一个文件

          Writer体系中可以操作文件的对象是FileWriter

      代码

         FileReader fr=new FileReader(a.txt);

         问自己:是否需要提高效率?

         是:加入Reader体系中的缓冲区:BufferedReader

         BufferedReader bufr=new BufferedReader(fr);

         FileWriter fw=new FileWriter(g.txt);

         问自己:是否需要提高效率?

         是:加入Reader体系中的缓冲区:BufferedWriter

         BufferedWriter bufw=new BufferedWriter(fw);

  5.2 第二个 需求:将键盘录入的的数据保存到一个文件中。

         这个需求中,有源和目的都存在

          分别分析:

         A 源:InputStream Reader

          是不是纯文本?   是,Reader

        设备:键盘。对应的对象是System.in

        不是选择Reader吗?System.in对应的不是字节流吗

        为了操作键盘的文本数据方便。可以转成字符流,按照字符串操作是最方便的。

        所以,既然明确了Reader,就将System.in转成Reader

        用到Reader体系中转换流InputStreamReader

        InputStreamReader isr=new InputStreamReader(Sysem.in);

        需要提高效率吗?需要  BufferedReader

        BufferedReader bufr=new BufferedReader(isr); 

 B目的 OutputStream  Writer

      是否是纯文本?是 Writer

      设备:硬盘,一个文件。使用FileWriter

     FileWriter fw=new FileWriter(c.txt);

      需要提高效率吗?需要,

      BufferedWriter bufw=new BufferedWriter(fw);

 5.3第三个需求:想要把录入的数据按照指定的编码表(UTF-8),将数据存到文件中。

      目的:OutputStream Writer

      是否是纯文本?是,Writer

      设备:键盘,一个文件,使用FileWriter 

      但是,存储时,需要加入指定的编码表,而指定的编码表,只有转换流才可以指定。

      所以要使用的对象是OutputStreamWriter

      而该转换流对象要接收字节输出流,而且还可以操作的文件的字节输出流,FileOutputStream

      OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(c.txt),UTF-8);

      需要提高效率吗?需要

      BufferedWriter bufw=new BufferedWriter(osw);

 

总结

所以,记住,转换流什么时候用呢?

 字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流。

    练习

将一个文本数据打印到控制台上,要按照以上格式完成三个明确

   1)源:InputStream  Reader

      是否是纯文本数据?是,Reader

      设备:硬盘上的文件。FileReader

      是否需要提高效率?是  BufferedReader

BufferedReader bufr=new BufferedReader(new FileReader(filename));

   2)目的  OutputStream  Writer

      是否纯文本数据?否,OutputStream   需要用到转换流 OutputStreamWriter

      设备:控制台。System.out

       是否需要提高效率?是  BufferedWriter

    BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));

6、改变标准输入输出流

 需求:复制文件

 
 
class TransStreamDemo
{
public static void Main(String[]args) throws IOException
{
//键盘录入
BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("out.txt")));
//但是目的地要改动,存到文件里
BufferedWiter bufw=new BufferedWriter(new InputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
//System.out.println(line.toUpperCase());
bufw.write(line.toUpperCase());
bufw.newLine();//换行   
bufw.flush();
}
bufr.close();
}
}

 System中提供一个方法,可以改变标准输入和标准输出

static void setIn(InputStream in) 

          重新分配“标准”输入流。 

static void setOut(PrintStream out) 

          重新分配“标准”输出流。 

这样就可以不用改动,完成复制。

改动目的即可。

 

 

   

 

7、异常日志信息

实际开发中, 当程序在执行时出现问题并是不希望直接打印给用户看的,图形界面也不会有控制台,而是需要作为文件存储起来,方便程序员查看,并及时调试程序,优化代码的。这就需要异常日志文件。

   

 

 

 

 

 

 

   8IO流——系统信息存进硬盘文件

       void list(PrintStream out) 

          将属性列表输出到指定的输出流。 

        void list(PrintWriter out) 

          将属性列表输出到指定的输出流。

 

 

流的基本应用小结:

1)流是用来处理数据的。

2)处理数据时,一定要先明确数据源,与数据目的地(数据汇)。

3)数据源可以是文件,可以是键盘。

4)数据目的地可以是文件、显示器或者其他设备。

5)而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等。


--- Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值