黑马程序员_Java基础——IO框架(上)(第5篇)

来源:互联网 发布:布兰诗歌 知乎 编辑:程序博客网 时间:2024/05/22 03:51

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

一、概述

    在我看来,IO框架相比于集合框架要复杂得多,许多人肯定不这样认为,但是本人在学习的过程中确实被整得晕头转向,也许到现在还没转过弯儿来呢!那么什么是IO流呢?简单来说就是用于处理设备之间数据传输的东西。在Java中操作数据就是通过流的方式。在硬盘上,文件是数据最常见的表现形式,因而对文件的操作也是IO流最常见的用途。按照流向来分的话,流可分为输出流和输入流。按照操作的数据来分的话又可以分为字符流和字节流。

    IO流有4个基本的抽象类,分别是字符流抽象基类Reader、Writer,字节流抽象基类InputStream、OutputStream。这4个基类下又分别拥有自己的装饰类,即使增强类,BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,都是以各自基类的名称为结尾,一一对应的。对于字节流和字符流的转换,Java中也专门提供了解决方案,就是Reader和Writer下的InputStreamReader、OutputStreamWriter两个转换流。其他的一些流也就不再赘述,下面图例一一明了。


二、Writer、Reader
1.FileWriter

    Java文档中对FileWriter的描述为用来写入文件字符的便捷类。确实对一开始接触IO流的初学者来说,这个类无疑是具有指导意义的。初始化一个FileWriter对象就会在硬盘上创建一个文件,会根据参数的设定确定是否覆盖原文件。关于这个类更多的也没什么可以多说的,举个例子就一目了然了。

//在硬盘上创建一个文本文件并向里面写入一些东西。

import java.io.*;class FileWriterDemo{public static void main(String[] args){FileWriter fw = null;try{//fw = new FileWriter("D:\\demo.txt");//这种方式创建的文件会覆盖已有的文件fw = new FileWriter("D:\\demo.txt", true);//这种初始化方式会判断,如果已有文件,则续写,没有,则创建,不会覆盖原有文件fw.write("asdhashdasdasjkdasdaskkjhsd");fw.flush();}catch (IOException e){System.out.println(e.toString());}finally{try{if(fw != null)fw.close();}catch (IOException e){System.out.println(e.toString());}}}}
这段代码看上去挺复杂,其实大部分都是在对异常的处理,核心代码就是try中的三句,相当的简单。

2.FileReader
    FileReader用于对文件字符读取的便捷类。这个类可以很放方便的对文件的字符进行读取。初始化一个FileReader对象,其参数中的表示要读取文件,必须存在,否则会抛出文件找不到异常。还是举个例子来讲,更清晰些,也更能便于理解。

//读取一个文本文件E:\\Code\\TreeSetTest.java

import java.io.*;class FileReaderDemo{public static void main(String[] args)throws IOException{FileReader fr = new FileReader("E:\\Code\\TreeSetTest.java");//一定得保证文件存在,否则会报文件找不到异常/*//第一种方式,一个一个的读,读一个打一个int ch;while((ch = fr.read()) != -1){System.out.print((char)ch);}*///第二种读取方式,读一组存入数组中,然后打印出来char[] buf = new char[1024];int len;while((len = fr.read(buf)) != -1){System.out.print(new String(buf, 0, len));}fr.close();}}
为了更清晰直观的理解流的学习,我把异常处理的部分直接抛出去了。其中注释中是一个字符一个字符的读取,读一次打印一次,这是最原始的方式。

从这里我们可以知道,流其实很简单,无非就是读和写,读和写一起组合使用便能够实现简单的文本文件的拷贝。具体示例如下。

//拷贝文本文件

import java.io.*;class CopyWenBenWenJian{public static void main(String[] args)throws IOException{FileWriter fw = new FileWriter("D:\\Copy_TreeSetTest.java");FileReader fr = new FileReader("E:\\Code\\TreeSetTest.java");char[] buf = new char[1024];int len;while((len = fr.read(buf)) != -1)//读进数组中{fw.write(buf, 0, len);//从数组写入文件中fw.flush();}fr.close();fw.close();}}
三、装饰设计模式

    何为装饰设计模式呢?简单来说,当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供增强功能,那么自定义的该类就被称为装饰类。装饰类通常会通过构造方法接受被装饰的类对象,并基于被装饰的类的功能,提供更强的增强功能。

    那么有同学可能会对装饰类和继承会有疑问。为什么要使用装饰类?继承也是可以实现的啊?简单来说,装饰模式比继承更加的灵活,如果一个体系中的所有的类都要增强,那么你会发现,继承的体系将会相当的臃肿,而且代码的重复率相当的高。那么在这个体系中定义装饰类,便会降低类与类之间的关系,避免了大量的继承而使得整个体系的臃肿不堪。

//装饰类的基本示例

class Person{public void chiFan(){System.out.println("吃饭");}}class SuperPerson{private Person p;SuperPerson(Person p){this.p = p;}public void superChiFan(){System.out.println("开胃酒");p.chiFan();System.out.println("甜点");System.out.println("来一根");}}class ZhuangShiDemo{public static void main(String[] args){Person p = new Person();p.chiFan();System.out.println();SuperPerson sp = new SuperPerson(p);sp.superChiFan();}}
3.BufferedReader
    BufferedReader为Reader的装饰类,是一个增强类。其具体用法与Reader中的其他流大同小异,只是其提供了更强的、效率更高的功能。比如其重写了int read();和int read(char[], int, int);方法,并增强提供了读取行的方法String readLine();方法。

//自己实现一个Reader的增强类MyBufferedReader

import java.io.*;class MyBufferedReader extends Reader{private Reader fr = null;MyBufferedReader(Reader fr){this.fr = fr;}public String MyReadLine()throws IOException{StringBuilder sb = new StringBuilder();int ch;while((ch = fr.read()) != -1){if(ch == '\r')continue;if(ch == '\n')return sb.toString();sb.append((char)ch);}if(sb.length() != 0)return sb.toString();return null;}public void close()throws IOException{fr.close();//使用子类自己的close()方法}public int read(char[] cbuf, int off, int length)throws IOException{return fr.read(cbuf, off, length);}}
4.InputStream、OutputStream
    字节流的操作和字符流大同小异,只不过字符流操作的文本,字节流可以操作图片、mp3等媒体文件,其使用的范围更加的广泛。下面通过一个拷贝mp3的例子来说明下。

//拷贝mp3

import java.io.*;class Copy_TuPian{public static void main(String[] args)throws IOException{BufferedInputStream fis = new BufferedInputStream(new FileInputStream("E:\\Code\\如果没有你.mp3"));BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("E:\\Code\\Copy_如果没有你.mp3"));byte[] buf = new byte[1024];int len;while((len = fis.read(buf)) != -1){fos.write(buf, 0, len);}fis.close();fos.close();}}
5.InputStreamReader、OutputstreamWriter
转换流可以将字节转换成字符,原因在于,其将获得到的字节通过查编码表获取到指定对应字符,其就是基于 字节流 + 编码表,没有转换就没有字符流,所以凡是操作设备上的文本数据,涉及编码转换都必须使用转换流。
    转换流的一个最特殊的运用就是标准输入和标准输出。
    标准输入(键盘录入):BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
    标准输出(屏幕):BufferedWrite bufw = new BufferedWriter(new OutputStreamWriter(System.out));

四、总结-流操作规律

    通过以上的学习,我们不难发现,流就是读和写的操作,明确源和目的之后,就很好操作了。
--明确源和目的地
数据源:就是从哪里读取数据,可以使用的两个体系:InputStream、Reader
目的地:就是要往哪里写入数据,可以使用的两个体系为:OutputStream、Writer
--操作的数据是否纯文本
如果是:读-Reader,写-Writer
若不是:读-InputStream,写-OutputStream
--虽然明确了体系,但是体系中有太多的对象,到底用哪个?
数据源对应的设备:硬盘(File)、内存(数组)、键盘(System.in)
目的地对应的设备:硬盘(File)、内存(数组)、控制台(System.out)
--需要在基本操作上附加其他功能吗?比如缓冲
如果需要就进行装饰

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

0 0
原创粉丝点击