[三]JavaIO之IO体系类整体设计思路 流的概念以及…
2018-09-10 01:03:27来源:博客园 阅读 ()
1.流
流的字面含义
物质 一个地方 流向了 另一个地方 |
主体 | 人 人从一个地方到了另一个地方 |
源/目的 | 学校/家 |
方向 | 回家或者返校 图中的两个箭头 |
中间形式 | 火车和汽车 |
1.1流到底是什么
源/主体内容/方向
水桶, 作为一个容器,他就是 源
里面可能装了水,也可能装了酒,还可能装了别的, 这就是数据形式主体
箭头表示方向,到底是往里面流还是往外抽
|
中间形式 我们都知道,水管可不全都是一种规格的,就拿家里装修常用的水管就有 4/6分管 两种 如果有一个阀门或者水龙头是6分管,而你接入桶里面的是4分管 怎么办? 显然,你会找一个转接头一类的东西,这就是下图中的黄色,橙红色,绿色代表的部分,他们就是不同的水管 通过转接头与另外一种规格的水管能够连接起来,这就是中间形式 |
抽水模型中的流 在这个例子中,流就是对于抽水这一过程的抽象描述. 一个水管里面的水的走向, 设定好了之后, 就是固定了的, 他要么往这头, 要么往另一头 而且,他肯定有一个源头/目的,水管得水不能凭空来,水管也不能凭空抽取水 另外,水管显然不仅仅只是能抽取水, 他还可以输送别的液体,比如酒,水,饮料,酱油醋...... 而且,如果有了各种不同规格的水管以及转接头,你的这个管道将会更加强大 所以说,容器 桶 接上了水管,就有能力提供水或者存储水,他就是一个流 如果这个流在整合上各种不同规格的转接头和水管,能力将会大大提升 |
1.2程序语言中的流的主要概念
含义/源/方向/数据形式/中间形式 |
流的含义:
在程序设计中,流是对于数据流动传输的一种抽象描述
任何有能力产出数据的数据源,或者有能力接受数据的接收端对象都是一个流 (也就是上面例子中的一个容器接上水管)
|
流的源和目的:
数据可能从本地文件读取,或者写入, 也可能发送到网络上,这就是源和目的
|
流的方向:
同水管里面的流水一样,也是只有两个方向,流进或者流出,也就是我们常说的输入 和 输出
|
流的数据形式: 数据的具体形式就是流传送的内容,可能是字节,也能是字符,这就是数据的形式 |
流的中间形式: 对于任何一个流对它的功能进行一些必要的扩充,就好像接上了转接头的流可以接到其他规格的水管一样 在一个流的基础上 包装,装饰上其他的一些功能,流就会变得更加强大 |
1.3 流相关概念详细解读
1.3.1 流的源和目的
1.文件
最基本的一个数据源就是我们前文提到过的文件,文件不仅java中有,其他语言中也拥有文件的概念
|
2.字节数组
数据最基本的单位是字节
数组是在程序设计中,为了处理方便, 把具有相同类型的若干变量按有序的形式组织起来的一种形式
这些按序排列的同类数据元素的集合称为数组
所以字节数组,自然是为了更方便操作字节的一种数据组织形式
|
3. 字符数组/String对象
既然数组可以简化更方便的进行操作,而且也有字节数组
是不是还应该有字符数组呢?
而且,java中的String对象 ,它的内部实现也是char数组,java中使用char表示字符,这不就是字符数组么
|
4. 管道
"管道"的概念也是类似字面含义,一端输入,就可以从一端流出,就好像一个水管一样,
主要用来多线程之间直接进行数据交互,所以说数据来源也可能是一个管道
|
5.网络等
其他数据源比如网络等,java的强项就是WEB,从网络接收数据是再自然不过的事情
|
6.流 另外流本身也可以作为一种源,所以一个流的源可以来自另外的一个流 |
1.3.2 流的方向
流的方向很简单,只有两个方向,输入 或者 输出
|
1.3.3 流的数据形式
计算机存储数据是二进制的 0 1 序列
计算机中存储容量的最小的单位是位(bit)最基本的单位是字节(byte)
字节是通过网络传输信息(或在硬盘或内存中存储信息)的单位
也就是说任何其他形式的数据,都可以而且,最终也都是用字节来表示
所以数据最基本的形式就是字节
1 byte = 8 bit
|
我们的世界充满了各种符号
字符是表示数据和信息的字母、数字或其他符号
在电子计算机中,每一个字符与一个二进制编码相对应,这是一个编码的过程
|
所以说,数据的基本形式有 字节 和 字符两种形式 |
1.3.4流的中间形式
放学回家的例子,我们很清楚的知道,火车和汽车是我们 人的中间形式过程,经过转换(买票上车), 地上的人看不到我们了,看到的只是火车 对于流来说,中间形式是什么样子的呢? 比如我们想要把一个Int类型直接写入到文件中,怎么办呢? 我们是不是需要把这个类型的数据处理下 转换下呢 或者说包装下 就如同你坐上了车(车把你装了进去,形式就是车),总之就是要处理下 比如想要缓冲,按照行,按照字等等 这就是一种中间形式,后面我们会详细介绍涉及到的中间形式 |
不过很显然,中间形式并没有向从某种数据源读取数据那么刚需 但是他会给你提供更多的功能,让你的流功能更加多变,扩展 如果有了中间形式,你可能就能够直接把一个int写入到文件上,这不是很方便么 |
1.3.5流的种类-基本功能 扩展功能
想要完成一个IO类库的基本功能,只需要把握住三点 |
1. 流的源和目的
2. 流的数据形式
3. 流的方向
|
想要做得更好就需要把握好流的中间形式,提供更强大的功能 |
流的源和目的 | 文件 / 字节数组 /管道 /字符数组/String对象 / 网络 / 流 |
流的数据形式 | 字符 / 字节 |
流的方向 | 输入 / 输出 |
文件(源) | 输入 | 字节 |
文件(源) | 输入 | 字符 |
文件(目的地) | 输出 | 字节 |
文件(目的地) | 输出 | 字符 |
字节数组(源) | 输入 | 字节 |
字节数组(源) | 输入 | 字符 |
字节数组(目的地) | 输出 | 字节 |
字节数组(目的地) | 输出 | 字符 |
管道(源) | 输入 | 字节 |
管道(源) | 输入 | 字符 |
管道(目的地) | 输出 | 字节 |
管道(目的地) | 输出 | 字符 |
2. JAVA IO类库体系结构
2.1 流的四大家族
输入 | 字节 |
输出 | 字节 |
输入 | 字符 |
输出 | 字符 |
四种形式 | 输入字节 | 输出字节 | 输入字符 | 输出字符 |
Java中名称 | InputStream | OutPutStream | Reader | Writer |
可以看得出来在命名上,类库设计者的一些想法
把字节使用Stream作为后缀,或许因为字节是最基本的单位,所以他才是流Stream
我们平时阅读 read和书写write的都是字符,所以使用Reader 和 Writer表示字符的输入和输出也很自然
|
节点流与过滤流
2.2.1 InputStream
2.2.1.1 InputStream节点流
字节数组 | ByteArrayInputStream (java.io) |
文件 |
FileInputStream (java.io)
|
管道 |
PipedInputStream (java.io)
|
String |
|
对象 | ObjectInputStream (java.io) |
类名 | 功能 | 构造方法 |
ByteArrayInputStream | 从字节数组中读取数据,也就是从内存中读取数据 包含一个内部缓冲区,指向该字节数组
内部计数器跟踪 read 方法要提供的下一个字节
关闭 ByteArrayInputStream 无效
此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
|
ByteArrayInputStream(byte buf[]) ByteArrayInputStream(byte buf[], int offset, int length) 不是复制而来,直接指向地址 多参数的带偏移量 |
FileInputStream | 用于从文件中读取信息 | FileInputStream(String name) FileInputStream(File file) FileInputStream(FileDescriptor fdObj) 使用文件路径名 抽象路径名File 或者文件描述符 |
PipedInputStream | 产生用于写入相关Pipe的OutputStream的数据 实现管道化的概念 管道输入流应该连接到管道输出流; 管道输入流提供要写入管道输出流的所有数据字节 通常,数据由某个线程从 PipedInputStream 对象读取 并由其他线程将其写入到相应的 PipedOutputStream 不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程 |
PipedInputStream(PipedOutputStream src) PipedInputStream(PipedOutputStream src, int pipeSize) PipedInputStream() PipedInputStream(int pipeSize) |
弃用,如果条件允许可以考虑使用StringReader | ||
ObjectInputStream |
对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时
可以为应用程序提供对对象图形的持久存储
ObjectInputStream 用于恢复那些以前序列化的对象
其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。
|
ObjectInputStream(InputStream in) ObjectInputStream() |
SequenceInputStream (java.io) | 两个或者多个InputStream对象转换为单一的InputStream | SequenceInputStream(InputStream s1, InputStream s2) SequenceInputStream(Enumeration<? extends InputStream> e) |
2.2.1.2 InputStream过滤流
我们之前就提到过,希望能够有直接操作数据类型的流,通过这个流可以直接操作基本数据类型的读写,而不需要自己去处理字节或者字节数组等
也就是说我们希望能够对基本数据类型进行支持
|
IO是操作系统的瓶颈,如果过于频繁的直接对磁盘IO进行读写,势必会增加CPU的空闲,性能降低,我们希望能够有缓冲的功能
|
IDE开发工具的编辑器都有行号的标志,行号可以给我们提供很多的便捷性,所以希望能够跟踪展示行号 |
比如当我们用程序读取一行代码,识别其中的关键字 比如 int i = 0; 读取到int时,我们不知道他是不是关键字,可能是一个int0的变量名 读取到下一个的时候,发现是空格,我们才能确定,他就是一个关键字 但是下面的空格已经被读取了,我们可能希望接下来的扫描能够读取到空格,可是流是顺序的,被消费了就不存在了 所以希望能够把读取到的字节回退到原来的流中 |
DataInputStream (java.io)
BufferedInputStream (java.io)
LineNumberInputStream (java.io)
PushbackInputStream (java.io)
|
看下类图,黑色部分为装饰器模式的角色 节点流表示上面说到的节点流 ByteArrayInputStream/FileInputStream/PipedInputStream/ObjectInputStream/ FilterInputStream中包含一个InputStream属性(是你还有你) |
SocketInputStream (java.net)
CheckedInputStream (java.util.zip)
DeflaterInputStream (java.util.zip)
GZIPInputStream (java.util.zip)
InflaterInputStream (java.util.zip)
ZipInputStream (java.util.zip)
JarInputStream (java.util.jar)
|
2.2.2 OutputStream
2.2.2.1 OutputStream节点流
字节数组 | ByteArrayOutputStream (java.io) |
文件 |
FileOutputStream (java.io)
|
管道 |
PipedOutputStream (java.io)
|
对象 | ObjectOutputStream (java.io) |
ByteArrayOutputStream |
其中的数据被写入一个 byte 数组
缓冲区会随着数据的不断写入而自动增长, 可使用 toByteArray() 和 toString() 获取数据
关闭 ByteArrayOutputStream 无效
此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
|
ByteArrayOutputStream() ByteArrayOutputStream(int size) 无参会调用有参,设置默认值 |
FileOutputStream | 信息写入文件 | FileOutputStream(String name) FileOutputStream(String name, boolean append) FileOutputStream(File file) FileOutputStream(File file, boolean append) FileOutputStream(FileDescriptor fdObj) 与FileInputStream几乎一样,不同的是第二个参数用于设置是否是append追加 |
PipedOutputStream | 可以将管道输出流连接到管道输入流来创建通信管道 管道输出流是管道的发送端 通常,数据由某个线程写入 PipedOutputStream 对象 并由其他线程从连接的 PipedInputStream 读取 不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁 |
PipedOutputStream(PipedInputStream snk) PipedOutputStream() |
ObjectOutputStream | ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream 可以使用 ObjectInputStream 读取(重构)对象 通过在流中使用文件可以实现对象的持久存储 如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象 |
ObjectOutputStream(OutputStream out) ObjectOutputStream() |
2.2.2.2 OutputStream过滤流
基本数据类型支持/缓冲/便捷输出 |
DataOutputStream (java.io)
BufferedOutputStream (java.io)
PrintStream (java.io)
|
非IO包中的,但是却跟IO相关的一些功能点,跟OutputStream相关的类 |
SocketOutputStream (java.net)
CheckedOutputStream (java.util.zip)
DeflaterOutputStream (java.util.zip)
GZIPOutputStream (java.util.zip)
InflaterOutputStream (java.util.zip)
JarOutputStream (java.util.jar)
ZipOutputStream (java.util.zip)
|
2.2.3 Reader
2.2.3.1 Reader节点流
字符数组 | CharArrayReader (java.io) |
String | StringReader (java.io) |
文件 |
FileReader (java.io)
|
管道 |
PipedReader (java.io)
|
CharArrayReader | 实现一个可用作字符输入流的字符缓冲区 | CharArrayReader(char buf[]) CharArrayReader(char buf[], int offset, int length) |
StringReader | 其源为一个字符串的字符流 | StringReader(String s) |
FileReader | 用来读取字符文件的便捷类 | FileReader(String fileName) FileReader(File file) FileReader(FileDescriptor fd) |
PipedReader | 管道字符输入流 | PipedReader(PipedWriter src) PipedReader(PipedWriter src, int pipeSize) PipedReader() PipedReader(int pipeSize) |
InputStreamReader | 转换为Reader InputStreamReader 是字节流通向字符流的桥梁 它使用指定的 charset 读取字节并将其解码为字符 它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集 每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节 为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader |
InputStreamReader(InputStream in) InputStreamReader(InputStream in, String charsetName) InputStreamReader(InputStream in, Charset cs) InputStreamReader(InputStream in, CharsetDecoder dec) 构造方法很清晰,接受一个InputStream 并且可以自定义字符编码 |
属于适配器模式中的对象适配器模式
Reader 是Target
InputStream 是 被适配者 Adaptee
InputStreamReader 是 Adapter
|
2.2.3.2 Reader过滤流
BufferedReader (java.io)
LineNumberReader (java.io)
PushbackReader (java.io)
|
在BufferedReader中,可以理解为只有一个具体的装饰器的简化版本
省略了抽象类
直接继承自Reader
BufferedReader 融合了Decoder 和 ConcreteDecoder两者
是你还有你 BufferedReader 是Reader 还有一个Reader
|
在FilterReader中就跟之前的字节流中的装饰器模式的应用基本一致了 FilterReader 表示抽象的装饰器部件 Decoder PushbackReader 表示具体的装饰器 是你还有你 FilterReader 是 Reader 还有 Reader |
2.2.4 Writer
字符数组 | CharArrayWriter (java.io) |
String | StringWriter (java.io) |
文件 |
FileWriter (java.io)
|
管道 |
PipedWriter (java.io)
|
CharArrayWriter |
实现一个可用作 Writer 的字符缓冲区
缓冲区会随向流中写入数据而自动增长 可使用 toCharArray() 和 toString() 获取数据。
在此类上调用 close() 无效
并且在关闭该流后可以调用此类中的各个方法,而不会产生任何 IOException
|
CharArrayWriter() CharArrayWriter(int initialSize) 内部包含char buf[] size为大小 构造方法用来初始化缓冲区 |
StringWriter | 将输出收集到一个字符缓冲区 StringBuffer的字符流,可以用来构造字符串 关闭 StringWriter 无效 此类中的方法在关闭该流后仍可被调用,而不会产生任何 IOException |
StringWriter() StringWriter(int initialSize) 构造方法初始化缓冲区 |
FileWriter | 用来写入字符文件的便捷类 类似FileReader继承自InputStreamReader 他继承自OutputStreamWriter |
FileWriter(String fileName) FileWriter(String fileName, boolean append) FileWriter(File file) FileWriter(File file, boolean append) FileWriter(FileDescriptor fd) 构造方法都是用来设置文件 |
PipedWriter | 管道字符流 | PipedWriter(PipedReader snk) PipedWriter() |
OutputStreamWriter | 类似InputStreamReader 作为转换器使用 OutputStreamWriter 是字符流通向字节流的桥梁 可使用指定的 charset 将要写入流中的字符编码成字节 使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集 每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器 为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中
例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
|
OutputStreamWriter(OutputStream out, String charsetName) OutputStreamWriter(OutputStream out) OutputStreamWriter(OutputStream out, Charset cs) OutputStreamWriter(OutputStream out, CharsetEncoder enc) 获取OutputStream然后进行转换,或者指定具体的字符编码 |
FilterWriter | 类似其他的Filter类,作为装饰器模式的Decoder角色 以便具体的装饰器角色可以使用 |
2.3 IO类层次结构总结
IO的逻辑功能设计点 由 数据源,流的方向,流的数据形式三部分组合而成,这个组合构成了IO的基本功能 另外还有扩展功能,扩展功能以基础功能作为依托,底层依赖基本功能 每种形式的基本功能和扩展功能构成了该形式的功能的集合 |
数据源形式比较多,但是对于流的数据形式以及流的方向是固定的 所以所有的类的基础,都是基于 流的数据形式以及流的方向的组合 也就是 字节输入 字节输出 字符输入 字符输出 这四个形式是固定的 分别使用 InputStream OutputStream Reader Writer来表示这四大家族 前面两个表示字节 后面两个表示字符 |
绝大多数的扩展都以 上面四个名词作为后缀,表示是他的家族成员 |
基本功能对于字节涉及下面几个关键词 ByteArray File Piped Object 扩展功能对于字节涉及涉及下面几个关键词
Data Buffered Pushback LineNumber print
|
基本功能对于字符涉及涉及下面几个关键词
CharArray String File Piped
扩展功能对于字符涉及涉及下面几个关键词 Buffered Print |
虽然四大家族都由基本功能以及扩展功能组成 但是字符和字节的实现形式却并不完全相同 字节流的扩展功能比较依赖装饰器角色FilterInputStream 以及 FilterOutputStream 但是字符流的扩展功能不完全依赖FilterReader 以及 FilterWriter |
数据源与四大家族的结合组合成了基本功能 也就是节点流 扩展功能点与四大家族的结合组成了扩展功能 也就是过滤流 |
另外还有几个工具一样的存在 SequenceInputStream 用于合并InputStream InputStreamReader 以及OutputStreamWriter 用于转换 使用了适配器模式 |
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Java的IO流 2020-05-14
- 7张图了解 Spring Cloud 的整体构架! 2020-05-13
- Spring 框架介绍 [Spring 优点][Spring 应用领域][体系结构] 2020-05-08
- 异常体系结构 throwable 2020-04-25
- kafka的基本体系结构 2020-04-17
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash