黑马程序员 第四章:IO流

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

 

IO流体系图

按照类型分为:字符流 
    字节流 
按照流向划分:
输入流:对流进行读的操作  
输出流对流进行写的操作 
IO流基类:
字符流: Reader       Writer
字节流: InputStream   OutputStream
Buffered与装饰设计模式
 
                                                  Buffered与装饰设计模式
 
装饰设计模式是对已有的功能进行增强。IO流中,通过  decorator 设计出了BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream这四个类。他们的共同点就是以高效的方式来对流进行操作。

装饰与继承图解:

通过例图,通过装饰设计模式设计的 Reader 体系明朗、结构简单。 而使用继承体系的Reader结构臃肿、扩展性极差。

 

装设计模式的设计思路:定义类,传入对象,基于已有功能,提供加强功能

 在IO中,比如: FileReader的 read() 是一个个读取字符。  但是为了更高效,在 BufferedReader中增强了read()而产生了readLine()。

有人说,用继承也挺好的。加上一个super.meals()就可以了。何必那么麻烦。
使用装饰设计模式,不仅避免了体系的臃肿,而且避免了单继承的局限性。为了继承而继承是大忌。可能NewPerson还有别的父类,如果继承了Person,就无法继承别的父类。而是用装饰设计模式,只需要定义一个成员对象、建立一个Person的构造函数。完全不影响程序的扩展性。
不同的时期,需求不同。可能某个功能过段时间就过时了,需要加强功能。这时,使用装饰设计模式最优。

总结:降低了类与类之间的联系、体系臃肿,提高了程序的扩展性
  装饰设计模式是对已有的功能进行增强,只不过提供了更强的功能。
所以,《装饰类与被装饰类通常属于同一体系》-----------重点。

Buffered为什么高效?
例:BufferedInputStream与FileInputStream

将InputStream套在BufferedInputStream中是一种很常见的编程模式。起着缓存的作用,用来改善InputStream的效率问题,而BufferedInputStream不能单独存在。 FileInputStream是读取文件作InputStream,所以你也可以将其嵌套在其中,改善FileInputStream的性能。

BufferedInputStream与FileInputStream的区别:
BufferedInputStream是尽可能的读取字节(能读多少是多少,撑死总比饿死强 -_-),而FileInputStream是定量读取,可能出现阻塞。
什么是阻塞?
假设有100个字节,使用BufferedInputStream一次性就可以读取完毕,但是使用FileInputStream一次只能读取10字节。也就是需要读取10次。在多线程的线程池与线程的问题一样。当线程不多时,开启线程和销毁线程体现不出,但是当访问数据量达到一定的量,这时一个非常消耗资源的事情。所以有了线程池的出现,根据系统的环境,自动或手动设置线程,达到最优的效果(少了浪费资源,多了系统拥挤)。  

BufferedInputStream与BufferedReader的区别
BufferedInputStream是用来对字节操作的流,而BufferedReader是对字符操作的流。
如果使用BufferedInputStream来操作中文,会出现乱码的情况。而是用BufferedReader不会,而且效率更高(一次读一行)

 

 

 

IO流---分析、使用世界

IO体系存在两大板块,字节流与字符流。两者主要区别在于对代码的操作。

字符流主要对字符串(2个字节)进行操作,主要操作纯文本文件,比如:txt文件。
字节流是对字节进行操作,操作非纯文本文件,比如:map文件

按照流向的划分为输入流、输出流
输入流又称源,源设备主要有:硬盘、内存、键盘
输出流又称目的,目的设备主要有:硬盘、内存、控制台

想要操作IO流,就需要明确操作类型、设备类型以及对象类型。

 下面,对这个需求进行分析
1.操作类型
纯文本文件--->字符流   Reader Writer
2.设备类型:
源设备类型:C盘--->硬盘
目的设备类型:D盘--->硬盘
3.对象类型
源对象:文本  FIleReader  需要提高效率吗?  必须的,谁不喜欢快  BufferedReader
目的对象:文本  选择1:FileWriter 需要提高效率吗?  需要    BufferedWriter
      选择2:PrintWriter
方法一:  

 方法二:

通过刚才的例子,我们简单的了解分析并书写一个简单的IO代码。但是IO到底有什么作用?什么时候使用IO流呢?
我们通过实际需求来分析。

切割:

 

原理:将一个正常的文件,按照指定的大小存储为一个不被任何软件解析的类型。也就是所谓的一个源对应多个目的。

切割图解:

 

合并:

原理: 通过容器(Vector)存储需要操作的文件。将其存为一个目的。 通过枚举与 SequenceInputStream 相关联。将其输出。

 

合并图解:

通过以上图例,得出了一些结论:
无论是切割还是合并。其实都是对数据的操作。切割,其实就是将一个文件的数据,存储到多个文件当中。说白了,也就是一个源对应多个目的。 而合并也是这个原理,不同的只是多个源(文件)数据对应一个目的(文件)。

那么,关于什么时候使用IO流、IO有什么作用这个问题,我们就有很明确的答案了。
    当我们需要对数据操作的时候就需要使用IO流,IO是用来处理数据之间的传输。

其实,对合并还有一种实现方法。
    定义 BufferedInputStream  srcFile = null;  通过循环的方法往 BufferedOutputStream 里添加数据。但是使用这种方法的扩展性比较差。在实际需求中,我们可能会对这些破损文件有其他的操作。使用这种方法,就需要重新定义一个循环来对其操作。在此就不再演示。将分析的图例贴出来。给大家参考:

 

 

Properties与IO流的关系:

Properties是用来读取配置文件。是Hashtable的子类。具有Map集合的特点,内部存储的是键值对。
通常与反射技术结合使用,通过Properties获取配置文件,然后通过Class.forName()获取该类的字节码文件对象

 常用方法:
 voidload(InputStream inStream) 
          从输入流中读取属性列表(键和元素对)。
 voidload(Reader reader) 
          按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
 StringgetProperty(String key) 
          用指定的键在此属性列表中搜索属性。
 ObjectsetProperty(String key, String value) 
          调用 Hashtable 的方法 put
 voidstore(Writer writer, String comments) comments 不可为中文
          以适合使用 load(Reader) 方法的格式,将此 Properties 表中的属性列表(键和元素对)写入输出字符。


 

properties----中文乱码

在中文操作系统下,java类型文件的编码默认设置为GBK,但是Proerties对资源文件的编码是ISO8859-1.所以编辑java文件的中文是不会出现问题,但是编辑Proerties资源的文件会出现问题。 

如果是数字呢?  将xxx的值换成111

编译数字是没有问题的。

如何解决(如果你使用的是Myeclipse  好像是废话。。):
直接修改Proerties资源文件的默认编码
打开Window->Perferences->General->ContentTypes:

修改后,再次打开配置文件,编译并保存。再次打开时,就正常显示。

如果还是不行,可以下载 ProertiesEditor,能够完美的解决这个问题。
http://huangrongyou.iteye.com/blog/1741298

 

 

 

 

 

IO之递归分析

概述:递归就是自己调用自己。递归作为一种算法在程序设计语言中被广泛使用。
程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。 

递归定义条件:
边界条件
边界执行段
递归执行段

下面,我们通过代码来说明:

图解:

 

现在,我们根据这个例题来对递归的定义条件进行分析。

边界条件:递归是自己调用自己,也就是说边界条件就是判断这个对象是不是传入本函数的对象。
                    在本题中,传入的对象是一个目录,而递归的条件也判断是否是目录 
边界执行段:其实就是递归执行段,满足递归条件后所执行的代码。一般都是调用递归函数。
递归执行段:在查找资料的时候,看过的几个博客都是叫做递归返回段,但是感觉不怎么恰当。返回段的意思是必须要有返回的代码。但是实际的需求可能是执行某一功能,而不是返回值。这段代码是递归需要执行的代码,还不如叫递归执行段。 意思是说:递归中执行的代码。

关于边界条件的作用:
递归即自己调用自己,如果没有判断条件的话,就是一个死循环。而且可能出现异常。就如我这个例子,边界条件是:判断是否是文件夹。如果不定义边界条件的话,直接调用自己。在再次调用的时候File[] files = file.listFiles()就直接抛出 异常。导致程序中断。
当定义了边界条件,执行到没有文件夹的目录,就会删除所有文件。依次逐渐返回上一层。
就如打开糖盒一样,打开一个糖盒,里面有一个糖盒和几个糖,打开还,还有一个糖盒和几个糖。如果一直存在糖盒的话,就要一直打开,直到没有为止。然后让其中的糖拿出来(有人说,我先拿糖不行啊,非要先打开糖盒。。。我只能说,我举个例子而已,你当写代码啊。。那么较真)。

 

 

 

IO流之ByteArrayInputStream、ByteArrayOutputStream

通过查看API,发现IO中InputStream、OutputStream是抽象类。而其中read()与write(itn b )是唯一的抽象方法。

InputStream read()源码部分

 

 

 

FileInputStream与FileOutputStream中复写的read()与write(int b)是通过native 本地方法实现的。所以在使用完之后需要通过close()关闭资源链接  

FileInputStream read()源码部分

 

 

 

而ByteArrayInputStream与ByteOutputStream中并没有 native 本地方法,而是直接对内存进行操作。所以就算close()也是没有实际意义

 

 

那么,ByteArrayInputStream与ByteArrayOutputStream到底有什么作用呢?
如果在程序在运行中产生一些临时文件,可以采用虚拟文件方式实现。而ByteArrayInputStream与ByteArrayOutputStream两个类可实现类拟于内存虚拟文件的功能。

以上是我对IO流的理解,如有不当之处,请各方豪杰指点。
本内容有些地方是参考别人,在其基础上加上自己的理解。
尊重版权:参考博客 
http://blog.csdn.net/oracle_microsoft/article/details/2634231  

 

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

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值