`
yidongkaifa
  • 浏览: 4038935 次
文章分类
社区版块
存档分类
最新评论

java IO包 与 装饰设计模式 浅谈

 
阅读更多

在API中,应用最多的另一个集合类群,就是IO集合了。它是以流的概念提供了对,标准输入及输出、硬盘文件、网络数据信息、字符串流及对象流内存等资源进行读写等操作方式。

一、那么先来了解是什么是流?流的概念。

流是指一连串流动的数据信号,是以先进先出的方式发送和接受数据的通道。这是个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接。而当程序需要写入数据的时候,就会开启一个通向目的地的流。可以想象数据好像在这其中“流”动一样,如下图:

输入流

输出流

二、java io包的流对象的关系

流按照操作数据对象类型的不同分为两种:字节流和字符流。

按照流的流向不同也分为两种:输入流与输出流。

而在众多的流对象类中,最重要的四个类,就是字节流与字符流的基类,也是抽象类。它们分别是

字节流基类:InputStream、OutputStream

字符流基本:Reader、Writer

下面是具体各流对象类之前的关系图:

字节流类与文件File关系图

字符流类关系图

三、重点IO类的浅谈

IO包中,核心思想是用到了装饰Facade的设计模式(本篇结尾处再详谈),这种用法使得后续添加进来的包装类可以非常强大的基本以前的类,提供更好更多的功能。比如BufferedInputStream类,在构造时需要提供一个InputStream对象传递进BufferedInputStream对象中。

InputStream: 是一个抽象类,表示所有字节类输入流的超类。

常用的方法:

int available()、void close()、int read()、int read(byte[] b)、int read(byte[] b, int off, int len)、long skip(long n)

FileInputStream :从文件系统中的某个文件中获得输入字节。通用用于操作图片、声音、视频等多媒体文件。若是字符文件可以考虑用FileReader。

常用的构造方法:

FileInputStream(File file) 、FileInputStream(String name)

常用方法:

int available()、void close()、int read()、int read(byte[] b)、int read(byte[] b, int off, int len)、long skip(long n) 其中available为返回下次调用时可以不受阻塞地从输入流中读取的字节数,skip为从输入流中跳过并丢弃 n 个字节的数据。

从方法中看到基本上来自于InputStream中声明的方法,只不对提供了对文件一种流思想的操作方法。一般为了增加功能包括缓存技术等,都被FileInputStream传递给另一些包装来进行处理,比如BufferedInputStream、DataInputStream等等。

BufferedInputStream:为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。

常用的构造方法:

BufferedInputStream(InputStream in) 、BufferedInputStream(InputStream in, int size)

常用方法:

基本上是InputStream中的方法,但它内部采用了数组缓存机制,提高了读取的效率,使得读取时间大大的缩小。

SequenceInputStream:表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。简单的讲,就可以将多个InputStream流接在一起,一起读取。

常用的构造方法:

SequenceInputStream(Enumeration<? extends InputStream> e)、 SequenceInputStream(InputStream s1, InputStream s2) 从构造方法中得知如有二个以上的InputStream流要串连在一起读时,可以将流add加入到Vector中,再用Vecotr的getElements()方法得到Enumeration,或者写个匿名内部类,在内部类中用List等类实现相应的Enumeration接口的方法即可。

常用的方法:

int available()、void close()、int read()、int read(byte[] b)、int read(byte[] b, int off, int len)等,也基本与InputStream方法是一样的,只不过增加了多个流串在一起读取。

OjectInputStream :ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。ObjectOutputStream是把内存的对象的状态值写入到一个输入流中,一般是文件对象等以文件保存起来。而OjectInputStream接受InputStrem时可接受FileInputStream,这样可以将以前持久化的Object对象,反持久化把状态重新读取出来。

常用的构造方法:

ObjectInputStream(InputStream in)

常用的构造方法:

除了从InputStream中拿多众多的read()、read(byte[] b)等方法外,还可以boolean readBoolean()、int readInt()、double readDouble()、Object readObject()等基本类型的read方法。

PipedInputStream:管道输入流应该连接到管道输出流;通常,数据由某个线程从PipedInputStream 对象读取,并由其他线程将其写入到相应的PipedOutputStream。当然也可以由某个线程从PipedOutputStream存入数据,然后由另一个线程从PipedInputStream中读取数据。因为PipedInputStream与PipedOutputStream的构造方法允许接受彼此对象,且read方法与write方法都是阻塞式的。

常用构造方法:

PipedInputStream(PipedOutputStream src)、 PipedInputStream( )

常用的方法:

void connect(PipedOutputStream src) 给构造了无参对象时,再用方法指定一管道输出流。其它的方法基本上可以从InputStream中找到。

ByteArrayInputStream:包含一个内部缓冲区,该缓冲区包含从流中读取的字节。关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 很显示它操作的只一个内存byte[]数组,所以不需要close()关闭资源。

常用的构造方法:

ByteArrayInputStream(byte[] buf) 、ByteArrayInputStream(byte[] buf, int offset, int length)

常用方法:

基本上没什么特殊的,都是InputStream中声明的方法。只不过提供了对内存byte[]数组以流思想操作的一种方式,当然这里不需要close()方法。

DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。若文件File中存储的是有序的数据类型byte数据,那么可以先new FileInputStream(name)然后,再传入此对象中,进行readInt等等读数据类型的操作。

常用的构造方法:

DataInputStream(InputStream in)

常用的方法:

除了从InputStream中获取的方法外,可以boolean readBoolean()、int readInt()、double readDouble()等几大基本数据类型。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

OutputStream:是一个抽象类,表示所有字节类输出流的超类。

常用的方法:

void close() 、 void flush() 、 void write(byte[] b) 、 void write(byte[] b, int off, int len) 、 void write(int b)

FileOutputStream :文件输出流是用于将数据写入 File的输出流。若是字符文件可以考虑用FileWriter。

常用的构造方法:
FileOutputStream(File file)、FileOutputStream(File file, boolean append)、FileOutputStream(String name)、FileOutputStream(String name, boolean append) 。 从两个构造函数的第二个参数boolean append可以明确知道,若为true则将写入的内容添入在文件结尾,否则就是覆盖文件中原始内容。

常用的方法:

基本上是基类OutputStream中的方法。

鉴于时间原因(为写这篇已经花了2小时了呐),这里不再一一阐述其它的OutputStream了,因这些OutputStream基本与它们的InputStream一样的都是基于基类,这里是OutputStream提供了一些增强的功能而已,就是构造时需要注意,需要传一个了OutputStream而已。 嗯,有个类PrintStream介绍下,虽然没有OutputStream的后缀,但它也属于OutputStream家族里面呢

PrintStream:为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。与其他输出流不同,PrintStream 永远不会抛出IOException;而且还可以在构造时指定boolean autoFlush,可自动刷新呢,当然只有在调用换行的println()方法或写入换行符或字节 ('\n') 时才刷新缓冲区数据。且println与print方法,有一堆的重载方法,支持各种基本数据类型的直接write或叫print呢。

常用的构造方法:

PrintStream(File file)、PrintStream(File file, String charset)、PrintStream(OutputStream out)、PrintStream(OutputStream out, boolean autoFlush)、PrintStream(OutputStream out, boolean autoFlush, String charset)、PrintStream(String fileName)、PrintStream(String fileName, String charset)

常用的方法:

除了从OutputStream那拿到一堆的write等方法外,还可能println(int i)、println(boolean b)、pirntln(double d)等等几个基本类型全支持直接println,甚至还支持println(char[] x)呢,给力吧。连System类中的Out对象,就是这个PrintStream对象呢,牛吧。意味着平时如何使用System.out.println...也可以怎么用println..。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Reader:是一个抽象类,表示所有字符类输入流的超类。

常用的方法:

void close()、int read()、int read(char[] cbuf)、int read(char[] cbuf, int off, int len)、read(CharBuffer target)、boolean ready()、void reset()、long skip(long n)

FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。若需要指定字符集来读取字符文件是可以考虑先构造FileInputStream对象,传入到InputStreamReader构造函数中,而InputStreamReader构造方法中支持可指定String charset的字符集。

常用的构造方法:

FileReader(File file)、FileReader(String fileName)

常用的方法:

没什么特别的,基本上都是Reader类中的方法,因它继承的是InputStreamReader方法,所以还有个小特别方法String getEncoding()得到此流使用的字符集。

BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。主要是可以用缓存技术呢,高效的进行读取,而且还有个牛逼方法String readLine()呢

常用的构造方法:

BufferedReader(Reader in)、 BufferedReader(Reader in, int sz)

常用的方法:

除了具体Reader中提供的方法外,还具有String readLine()方法用取一次性读取一行操作,读取的行中已去掉了行结束符的\r\n或\r,且若已到文件结尾时返回的是null,而普通的不管是字符流还是字节流read方法是若到结尾返回都是-1呢。

LineNumberReader:不在过多介绍,这是继承自BufferedReader类,且提供了一个带行号的操作方法int getLineNum()与void setLineNum(int num)而已。

InputStreamReader:是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。

常用的构造方法:

InputStreamReader(InputStream in)、InputStreamReader(InputStream in, Charset cs)、InputStreamReader(InputStream in, String charsetName)

常用的方法:

除了一个String getEncoding() 方法外,其它的基本上是基类Reader上声明的方法呢

常用的键盘输入片代代码为:

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


CharArrayReader:顾名思义应该是操作char[]数组的呢,所以在构造方法中必须是CharArrayReader(char[] buf) 、CharArrayReader(char[] buf, int offset, int length),而在方法中,基本上是用Reader中的声明方法,当然与ByteArrayInputStream很像,但有区别是的ByteArrayInputStream不需要close方法,调用close之后仍然可以使用,不会产生IOException,但CharArrayReader的close方法需要调用 ,且调用close()方法之后 ,再调用read等方法会产生IOException。

PipedReader: 与前面提供的PipedInputStream很类似,只不过PipedReader用来处理字符流输入的,其它在构造上,也像需要PipedWriter对象,方法上基本使用Reader方法。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Writer:是一个抽象类,表示所有字符类输出流的超类。

常用的方法:

void close()、void flush()、write(char[] cbuf)、void write(char[] cbuf, int off, int len)、write(int c)、write(String str)、write(String str, int off, int len)

FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。若需要指定字符集来读取字符文件是可以考虑先构造FileOutputStream对象,传入到OutputStreamWriter构造函数中,而OutputStreamWriter构造方法中支持可指定String charset的字符集。

常用的构造方法:

FileWriter(File file)、FileWriter(File file, boolean append)、FileWriter(String fileName)、FileWriter(String fileName, boolean append),同时append代表写入文件时,是否需要覆盖原有内容,true代表往文件结尾处追加内容。

常用的方法:

基本上与Writer方法一样,除了从OutputStreamWriter那得到String getCoding()外。

其它的类BufferedWriter(有缓存功能)、OutputStreamWriter(有字节流通向字符流且构造接受OutputStream)等等,基本上在实现思想上与对应的字节流相应的类如BufferedOutputStream差不多,都是接受相应自家的Writer类,然后方法嘛都基本上从Writer中拿出来,再介绍个超级牛逼的类PrintWriter。

PintWriter:向文本输出流打印对象的格式化表示形式。此类实现在 PrintStream 中的所有 print 方法。与PrintStream 类不同,如果启用了自动刷新,则只有在调用printlnprintfformat 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。

常用的构造方法:

PrintWriter(File file)、PrintWriter(File file, String charset)、PrintWriter(OutputStream out)、PrintWriter(OutputStream out, boolean autoFlush)、PrintWriter(String fileName)、PrintWriter(String fileName, String charset)、PrintWriter(Writer out)、PrintWriter(Writer out, boolean autoFlush) 说它牛逼,是说它对OutputStream 与Writer和File通吃呢,而且方法上很非常的给力。

常用的方法:

除了从Wirter那拿到一堆的write等方法外,还可能println(int i)、println(boolean b)、pirntln(double d)等等几个基本类型全支持直接println,甚至还支持println(char[] x)、println(Object obj)等等强啊。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

上面介绍完了所有的常用的字节流与字符流,下面介绍下File文件与RandomAccessFile

File:文件和目录路径名的抽象表示形式。而且文件是不可变的实例哦,一旦File被指定了路径名,此路径名将永远不会改变。除非重新new 个File了。

常用的构造方法:

File(File parent, String child)、File(String pathname)、File(String parent, String child)、File(URI uri)

常用的方法:

boolean createNewFile()、 boolean delete()、 boolean exists()、 String getAbsolutePath()、String getName()、String getParent()、File getParentFile()、 String getPath()、 boolean isDirectory()、 boolean isFile()、boolean isHidden()、long lastModified()、long length()、 String[] list() 、String[] list(FilenameFilter filter) 、 File[] listFiles() 、 File[] listFiles(FileFilter filter)、File[] listFiles(FilenameFilter filter)、 boolean mkdir()、 boolean mkdirs()等等一系列的方法。

    File f = new File("D:\\abc\\test.txt");
    if(!f.exists())
	f.createNewFile();//提前D:\abc是存在的

RandomAccessFile:比较特殊哦,它是继续自Object中的类,但属于io包中,是对File进行操作,且可以读read也可以写write,内部存在的一个指针指向当前文件操作的位置那么此时的读与写都是基于此position位置的。

常用的构造方法:

RandomAccessFile(File file, String mode)、RandomAccessFile(String name, String mode)。注意里的mode指定是操作文件是采用的模式一般为只读"r"或读写“rw”。

常用的方法:

void close() 、long getFilePointer() 返回此文件中的当前偏移量。 、 long length() 返回此文件的长度。 int read() 、int read(byte[] b)、
int read(byte[] b, int off, int len) 、 boolean readBoolean() 、 byte readByte() 、 char readChar() 、 double readDouble() 、 float readFloat() 、 int readInt() 、
String readLine() 、long readLong() 、 short readShort() 、 String readUTF() 、 void seek(long pos) 指针移到指定位置、 void setLength(long newLength) 、
int skipBytes(int n)、 void write(byte[] b) 、 void write(byte[] b, int off, int len) 、void write(int b) 、void writeBoolean(boolean v)、 void writeByte(int v) 、
void writeBytes(String s) 、void writeChar(int v) 、void writeChars(String s) 、void writeDouble(double v) 、void writeFloat(float v) 、
void writeInt(int v) 、void writeLong(long v) 、void writeShort(int v) 、void writeUTF(String str) 使用 modified UTF-8 编码以与机器无关的方式将一个字符串写入该文件。 方法超级强大啊,既能支持读又写支持写,而且读写都可以支持用基本类型的如readInt,WriterInt的。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

装饰设计模式的浅谈:

当想要对已有的对象进行功能增加时,定可以定义类,将已有对象传入其于已有的功能中,并提供加强,那么自定义的该类就称为装饰类。

装饰类通常会通常构造方法接受被装饰的对象,并基于被装饰的对象功能,提供更强的功能。

装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之前的耦合度。

装饰类因为增加已有对象,具备的功能和已有的是相同的,只不过提供了更强功能,所以装饰类和被装饰类通常属于一个体系中的。

示例代码:

package com.pattern.decorator;

/**
 * 从本质来说,如果被装饰对象确实只有一个,那么Component与ConcreteCompoent类就可以合并了,如果只有一种装饰方法,那么
 * Decorator与ConcreteDecorate也就可合并,那么此时就只会有两个类ConcreteComponet类与ConcreteDecorate类了,这样就是
 * class ConcreteComponent{
 * 		public void operate{System.out.println("吃饭");}
 * }
 * class ConcreteDecorate extends ConcreteComponent{
 * 		private ConcreteComponent concreteComponent ;
 * 		public void operate{concreteComponent.operate();System.out.println("吃饭");}
 * 		...
 * }
 * 
 * 正是因为装配的方法是多样的,比如要 洗手  拿筷子 拿碗 听音乐等等,而且这些可以是无序的,
 * 这样我们就需要封闭这些变成,把它抽象成一个新的类decorate让它来继承 Component
 * (我们假设我们现在不只要装饰一个类了,我们要求可以装饰一群类,此时就要抽象出一个可以让所有的类都具有可装饰的功能的类了)
 * 这样我们就有了Component ConcreteComponentA ConcreteComponentB Decorator ConcreteDecoratorA ConcreteDecorateB ...
 * 
 * 我们就是要找到变化,然后隔离,封装抽象成一个类(抽象类或接口)
 * @author Administrator
 *
 */
public class DecorateDemo {
	
	public static void main(String[] args){
		Component eat = new ConcreteComponent();
		Decorator decorateA = new ConcreteDecoratorA();
		Decorator decorateB = new ConcreteDecoratorB();
		//第一种行为,装饰的结果,装饰通常也可以通常构造方法传入呢
		decorateA.setComponent(eat);
		decorateB.setComponent(decorateA);
		decorateB.operate();
		
		System.out.println("--------------------------------------------------");
		//第二种行为,装饰的结果
		decorateB.setComponent(eat);
		decorateA.setComponent(decorateB);
		decorateA.operate();
	}

}

interface Component{
	public void operate();
}

class ConcreteComponent implements Component{
	public void operate(){
		System.out.println("吃饭");
	}
}


abstract class Decorator implements Component{
	private Component component ;
	public void operate(){
		component.operate();
	}
	public void setComponent(Component component) {
		this.component = component;
	}
}

class ConcreteDecoratorA extends Decorator{
	private boolean addState ;
	
	public void operate(){
		super.operate();
		if (addState)
			System.out.println("洗手");
		else
			System.out.println("等会,再看会书");
	}

	public boolean isAddState() {
		return addState;
	}

	public void setAddState(boolean addState) {
		this.addState = addState;
	}
}

class ConcreteDecoratorB extends Decorator{
	public void operate(){
		super.operate();
		System.out.println("拿碗");
		this.addBehavior();
	}
	
	private void addBehavior(){
		System.out.println("打开CD机播音乐");
	}

}
分享到:
评论

相关推荐

    java IO教程,java IO教程,java IO教程

    java IO教程,java IO教程,java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程java IO教程java IO教程java IO教程java IO教程,java IO教程,java IO教程,java IO教程,java IO...

    java io包课件

    了解java.io包 运用File类对文件或目录的属性进行操作 理解流,理解输入/输出流的概念 运用FileInputStream类和FileOutputStream类读/写字节文件 运用FileReader类和FileWriter类配合BufferedReader类和...

    Java IO 与 装饰模式

    NULL 博文链接:https://lin252840.iteye.com/blog/546327

    浅谈java之IO学习经验

    浅谈IO学习经验,浅谈IO学习经验,浅谈IO学习经验,浅谈IO学习经验,浅谈IO学习经验

    java IO流精讲

    IO 简介,只看这篇,IO全部搞定,对于初学者来说,不可多得

    java.io包讲解

    专业的课程讲解 所有的程序都离不开信息的输入和输出。例如,从键盘读取数据、在网络上交换数据、打印报表、读写文件信息等,都要涉及数据输入输出的处理。...在Java中,处理数据流的类主要被放在java.io包中 。

    java学习笔记1(java io/nio)

    java学习笔记1(java io/nio)设计模式

    java IO系统与正则表达式

    java IO系统与正则表达式

    java IO 流浅谈

    最近学了java IO流 是个比较绕的东西,有时候很难理清它的头绪,即使当时清楚了,过一段时间后也会忘记,因此记录下来IO流中常用的几个类,以供大家参考,及本人以后复习

    Java教程之javaIO详解

    Java教程之javaIO详解Java教程之javaIO详解Java教程之javaIO详解

    java.io包详细解说

    java.io包详细解说,讲得很详细 同类文档:Java-从Decorator,Adapter模式看Java IO库,已上传

    IO流 javaio java 流

    IO流 javaio java 流

    java.io 包 .ppt

    使用Date 类获取系统当前时间 Calendar类的使用 使用 Random 类的对象生成随机数 Collection 类的对象的使用 HashMap 对象以键和值的关系形式存储数据

    java基础io包

    java基础io包,字符流和字节流 PPT

    java jsp IO包 教程 新手入门

    本资源具体讲述了java io包的使用及分类,本人感觉相比其它教程还是比较出色的,本人亲身体验过,肯定不欺骗,希望大家多多支持,踊跃留言

    java jdk io包类详解

    java的jdk源码解析,主要解析io、nio相关的类组织结构图

    java io 结构图

    java io 结构图java io 结构图

    Java IO_NIO

    1、Java IO_NIO 2、Java+IO.pdf

    java io 与java nio区别

    java频道\java io 与java nio区别.txt

    JAVA课件Java IO.ppt

    JAVA课件Java IO.ppt详细了解JAVA

Global site tag (gtag.js) - Google Analytics