Java: I/O(1/3)字节流与字符流的纵向与横向比较
2015-11-16 23:40
513 查看
摘要: java.io包中大部分内容属于字节流和字符流,涵盖了相当多的类。面对这些类,如果不进行有效的总结,即使有一定经验的Java developer也一样会感到(相当)混乱。本文将从纵、横两个维度来整理这部分内容。
横向归类:
纵向归类:
然而对于文本数据,由于存在编码问题比较麻烦,所以交由字符流处理。
装饰者模式就是在一个主体(被装饰者)的外部使用装饰类来进行装饰,对主体的行为根据不同的装饰者类进行不同的修改。单个的装饰类自根据自身特点对主体的行为进行部分改进,因此可以组合多个装饰类来对主体进行修改(在代码中表现为多层装饰类的嵌套)。
Java的I/O类设计应用了装饰者模式。单个的流对象主体,例如
如图:
从代码的角度来看:
装饰者模式从抽象的角度来说很容易理解,然而也存在一个很明显的缺点:装饰类过多。因此我们能看到java.io包中那么多的类。如果没有理解装饰者模式,即使有一定经验的Java developer也会感到混乱。
处理具体的文本数据使用字符流;
例如对于文件复制这样的操作来说,即使是文本文件的复制,我们对其具体的内容是什么并不关心,因此可以直接使用字节流。但当我们要从一个文本文件中读取内容,我们关心其具体的内容,所以使用字符流。
ByteArrayOutputSteam:将数据输出到字节数组(byte array)中,也就是内存,不用生成文件;
FileOutputStream:将数据输出到具体的文件;
PipedOutputStream:将数据输出到线程,即通过与PipedInputStream联合使用,将数据在不同的线程之间传递;
FilterOutputStream:装饰类的父类
BufferedOutputStream:使用了缓冲区,调用flush()才会清空缓冲区将数据写入文件。与普通OutputStream相比,由于不用频繁地与文件进行I/O数据传输(内存与磁盘之间,这将消耗大部分性能),而是在每次调用flush()时一次性地将一块数据在内存与磁盘中传输,因此会性能将得到提升(有NIO的影子);
DataOutputStream:用于方便地传输基础类型的数据,因此除了传统的write()外,还有一堆writeInt()、writeDouble、writeBoolean()等;
PrintStream:InputStream本来是适合用于非文本的二进制文件(如图片、声音文件等),而PrintStream则是在字节流中专门用于打印文本内容;
ByteArrayInputStream:从内存中读取数据;
FileInputStream:从文件中读取数据;
PipedInputStream:从一个线程中读取数据,从另一个线程中输出(PipedOutputStream),同一线程下使用者两个对象可能会造成线程死锁;
SequenceInputStream:将两个
FilterInputStream:装饰类的父类;
BufferedInputStream:使用了缓冲区,参考
DataInputStream:方便地读取基本类型的数据,因此除了基础的read()外,还有一堆readChar()、readDouble()、readInt()等;
CharArrayWriter:面向内存;
PipedWriter:面向线程;
PrintWriter:方便输出,特别是按格式输出printf();
StringWriter:使用StringBuilder来存放内容;
OutputStreamWriter:用于字符流与字节流之间的转换;
FileWriter:面向文件
FilterWriter:装饰类
CharArrayReader:面向内存;
PipedReader:面向线程;
InputStreamReader:用于字符流与字节流之间的转换;
FileReader:面向文件
FilterReader
NIO部分打算在(3/3)中发表。
Summary 总述
java.io包中的类非常繁多,但其实只要归成4类:InputStream&
OutputStream、
Reader&
Writer,由于功能和命名上都相当接近,因此只要掌握了其中一种,将会很容易理解其他3种。
横向归类:
InputStream&
OutputStream(字节流)、
Reader&
Writer(字符流).
纵向归类:
InputStream作为父类,其子类的角色和作用,并以此举一反三。
字节流
字节(byte)是计算机中基本数据单位,一切的计算机数据(或“文件”)都是由或多或少的字节组成,因此使用字节流,理论上可以处理一切计算机数据(文件),包括图像、音频、文本等。然而对于文本数据,由于存在编码问题比较麻烦,所以交由字符流处理。
字符流
1char=2byte,字符(char)的表示范围(2^16)是字节(byte)表示范围(2^8)的2^8=256倍。专门用于处理文本数据。历史
字节流在Java的初版(jdk 1.0)已经存在,字符流在jdk 1.1中加入,以替代字节流中处理字符的功能。装饰者模式
私以为,提到Java I/O的话,不能不提装饰者模式。装饰者模式就是在一个主体(被装饰者)的外部使用装饰类来进行装饰,对主体的行为根据不同的装饰者类进行不同的修改。单个的装饰类自根据自身特点对主体的行为进行部分改进,因此可以组合多个装饰类来对主体进行修改(在代码中表现为多层装饰类的嵌套)。
Java的I/O类设计应用了装饰者模式。单个的流对象主体,例如
InputStream的直接子类(Direct Subclasses)中,分别面向文件
FileInputStream、内存
ByteArrayInputStream、线程
PipedInputStream,而
InputStream的另一个直接子类
FileterInputStream为装饰类(的父类),分别定义了各种具体的装饰类(如
BufferedInputStream、
DataInputStream等)。
如图:
从代码的角度来看:
DataInputStream、
BufferedInputStream为装饰者,
FileInputStream为主体(被装饰者)
InputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(src))));
装饰者模式从抽象的角度来说很容易理解,然而也存在一个很明显的缺点:装饰类过多。因此我们能看到java.io包中那么多的类。如果没有理解装饰者模式,即使有一定经验的Java developer也会感到混乱。
结论
处理非文本数据使用字节流;处理具体的文本数据使用字符流;
例如对于文件复制这样的操作来说,即使是文本文件的复制,我们对其具体的内容是什么并不关心,因此可以直接使用字节流。但当我们要从一个文本文件中读取内容,我们关心其具体的内容,所以使用字符流。
Description 详细内容
篇幅所限,只列出常用的类,其余部分可参考Java API手册。继承关系图
字节流的继承关系
OutputStream
OutputStreamByteArrayOutputSteam:将数据输出到字节数组(byte array)中,也就是内存,不用生成文件;
FileOutputStream:将数据输出到具体的文件;
PipedOutputStream:将数据输出到线程,即通过与PipedInputStream联合使用,将数据在不同的线程之间传递;
FilterOutputStream:装饰类的父类
BufferedOutputStream:使用了缓冲区,调用flush()才会清空缓冲区将数据写入文件。与普通OutputStream相比,由于不用频繁地与文件进行I/O数据传输(内存与磁盘之间,这将消耗大部分性能),而是在每次调用flush()时一次性地将一块数据在内存与磁盘中传输,因此会性能将得到提升(有NIO的影子);
DataOutputStream:用于方便地传输基础类型的数据,因此除了传统的write()外,还有一堆writeInt()、writeDouble、writeBoolean()等;
PrintStream:InputStream本来是适合用于非文本的二进制文件(如图片、声音文件等),而PrintStream则是在字节流中专门用于打印文本内容;
InputStream
InputStreamByteArrayInputStream:从内存中读取数据;
FileInputStream:从文件中读取数据;
PipedInputStream:从一个线程中读取数据,从另一个线程中输出(PipedOutputStream),同一线程下使用者两个对象可能会造成线程死锁;
SequenceInputStream:将两个
InputStream合并成一个;
FilterInputStream:装饰类的父类;
BufferedInputStream:使用了缓冲区,参考
BufferedOutputStream;
DataInputStream:方便地读取基本类型的数据,因此除了基础的read()外,还有一堆readChar()、readDouble()、readInt()等;
字符流的继承关系
Writer
BufferedWriter:缓冲区;CharArrayWriter:面向内存;
PipedWriter:面向线程;
PrintWriter:方便输出,特别是按格式输出printf();
StringWriter:使用StringBuilder来存放内容;
OutputStreamWriter:用于字符流与字节流之间的转换;
FileWriter:面向文件
FilterWriter:装饰类
Reader
BufferedReader:缓冲区;CharArrayReader:面向内存;
PipedReader:面向线程;
InputStreamReader:用于字符流与字节流之间的转换;
FileReader:面向文件
FilterReader
Others 其他
本篇作为Java I/O系列之一,只分析了字节流和字符流。其他Java I/O内容如File、RandomAccessFile、System类的I/O支持和重定向、字符编码、文件压缩、对象序列化和Scanner等内容会在(2/3)中发表。NIO部分打算在(3/3)中发表。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统