IO即数据读写。数据是应用的中心要素,而数据读写的能力和可扩展性是编程平台的基础支撑。

概念框架

  • 方式: 字节流 Byte 和 字符流 Char

  • 方向: 输入 Input 和 输出 Output ; 读 Reader 和 写 Writer

  • 源: 字符串 String, 数组 Array, 对象 Object, 文件 File, 通道 Channel, 管道 Pipe, 过滤器 Filter,控制台 Console, 网络 Network Link ; 一切可产生/接收数据的 Data

  • 性能: 带缓冲和不带缓冲的

  • 行为: Readable, Appendable, Closable, Flushable, Serializable/Externalizable

概念组合

  • 方式、方向、源、行为四个维度可以组合出各种特性的IO流。JavaIO框架采用装饰器模式,可以在现有IO流的基础上添加新的IO特性,生成更强功能的IO流,体现了读写能力的可扩展性。

  • 比如要构造一个带缓冲的文本文件读取流: File -> FileInputStream -> InputStreamReader -> FileReader -> BufferedFileReader . 【文本:字符流, 文件:源, 读:输入方向, 带缓冲的:性能】

  • 读写耗时的字符输入输出流可以使用缓冲来提升性能,比如文件读写、网络流读写等。这是由于每个待读写的字符都要经过【读写字节、字节/字符转换】两个操作。缓冲实际上是将大量单个的读写/转换或多个小粒度的读写/转换操作,转换为一个大的单个的批量读写/转换操作。

字节流

  • 字节输入流:InputStream, BufferedInputStream, FileInputStream, ByteArrayInputStream, PipedInputStream, FilterInputStream, DataInputStream, ObjectInputStream;

  • 字节输出流: OuputStream, BufferedOuputStream, FileOuputStream, ByteArrayOuputStream, PipedOuputStream, FilterOuputStream, DataOuputStream, ObjectOuputStream, PrintStream;

字符流

  • 字符输入流: Reader, BufferedReader, FileReader, CharArrayReader, PipedReader, FilterReader, StringReader, LineNumberReader;

  • 字符输出流: Writer, BufferedWriter, FileWriter, CharArrayWriter, PipedWriter, FilterWriter, StringWriter, PrintWriter;

字节流与字符流之间的转化

  • InputStreamReader:输入字节流转化为输入字符流

  • OutStreamWriter: 输出字符流转化为输出字节流

其它

  • Bits: 原子类型 boolean, short, int, long, float, double 到其字节数组表示之间的转化(大端字节序);将原子类型转化为字节数组使用 >>>8 运算符,高位字节在数组低索引; 将字节数组转化为原子类型则采用 [&0xFF, <<8, +] 运算符 。

  • 装饰器模式:多个类实现同一个接口,并且这些实现类均持有一个该接口的引用,通过构造器传入,从而可以在这些实现类的基础上任意动态地组合叠加,构造出所需特性的实现来。装饰器模式可以实现数学公式/逻辑公式运算函数。

实现

  • 在IO流的实现类中,通常有一个 【Char[],Byte[], CharBuffer, StringBuffer, ByteBuffer】的成员数组或成员对象。将成员数组/对象里的数据写到方法里给定的参数数组或返回值,即为读实现;将方法里给定的参数数组写到成员数组或成员对象里,即为写实现。读写数据本质上就是数据在不同源之间的拷贝实现。
  • IO流通常是会实现读写单个字节/字符、读写字节数组/字符数组、跳过若干字节/字符的功能。成员 【next,pos,mark,count】 用于标识数据读写位置;mark 与 reset 方法组合可实现重复读写。
  • 要实现一个自定义的 Reader, 可参考 StringReader 实现;StringReader 可以将字符串作为字符流来读取,内部成员为String;而 StringWriter 内部成员为线程安全的 StringBuffer。两者均要考虑并发读写的问题,使用一个 Object 锁进行互斥访问。
  • FileReader 是文本文件读取流,通过继承 InputStreamReader, 转化 FileInputStream 而得。因文件是对磁盘字节数据的抽象,因此要获得人类可读的文本,必然存在从字节流到字符流的转换。
  • InputStreamReader 使用 StreamDecoder 将字节流转换为指定字符编码的字符流,后续读操作直接委托 StreamDecoder 读取;StreamDecoder 是一个字节解码器, 是 Reader 实现类。OutputStreamWriter 使用 StreamEncoder 将字符流转换为指定字符编码的字节流,后续写操作直接委托 StreamEncoder 写入底层 OutputStream;StreamEncoder 是一个 Writer 实现类。
  • FilterReader, FilterWriter, FilterInputStream, FilterOutputStream: IO流的抽象类,分别持有一个【Reader,Writer,InputStream, OutputStream】, 自定义 IO 流可以通过继承 FilterXXX 来实现。CommonIO库里 ProxyReader, ProxyWriter 分别提供了 Reader, Writer 的一个示例实现, java.io.DataInputStream 提供了 FilterInputStream 的一个示例实现,java.io.PrintStream 提供了 FilterOutputStream 的一个示例实现。
  • BufferedReader: 提供了缓冲读及读行的功能。BufferedReader 主要成员为 【Reader in, char[defaultsize=8192] cb, int nextChar, int nChars, int markedChar】; nextChar 指示将要读取的字符位置, nChars 指示可以读取字符的终止位置, markedChar 表示被标记的将要读取字符的位置; BufferedReader 从字符流 in 中读取字符预存入缓冲字符数组 cb 中,然后在需要的时候从 cb 中读取字符。BufferedReader 的实现由 fill 和 read, readLine 共同完成。当缓冲字符数组的字符数不足于填充要读取的参数数组时,就会使用 fill 方法从输入流 in 中读取数据再进行填充;使用 System.arraycopy 方法

public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 拷贝字符。

  • PipedReader: 管道输入流,必须从 PipedWriter 中读取。底层实现有两个线程、两个位置索引以及一个字符数组。两个线程分别是读线程 readSide 和 写线程 writeSide, 两个位置索引分别用于指示字符数组中将要写的位置和将要读的位置。字符数组是一个循环队列,默认大小为 1024 chars 。初始化时必须将 PipedReader 的输入连接至 PipedWriter 。读实现方法中,即是将底层字符数组拷贝到方法中的参数数组。PipedWriter 的实现相对简单,其输出连接至 PipedReader; PipedWriter 的写就是 PipedReader 的读,因此 PipedWriter 的方法实现委托给 PipedReader 引用的方法。

文件

  • 文件相关的类: File, RandomAccessFile, FileDescriptor, FileChannel, FilePermission, FilePermissionCollection, FileFilter, FileSystem, UnixFileSystem ;

  • 文件 File: 唯一性路径标识【目录路径/文件名[.文件扩展名]】、文件元信息【描述符、类型、大小、创建时间、最近访问时间、节点信息】、文件访问权限【读/写/执行组合】等; File 的操作会先使用 SecurityManager 检查访问权限,然后通过 FileSystem 判断和操作。

  • 构造可以实际读写的文件输入输出流需要使用 FileInputStream, FileOutputStream, FileReader, FileWriter, BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream 来包装 File ,比如 new BufferedReader(new FileReader(new File(filename))) 。

  • FileChannel: 操作文件内容的通道;FileChannel 是线程安全的,使用 java.nio 引入的高性能机制来实现。

  • 文件描述符 FileDescriptor : 用于操作打开的文件、网络socket、字节流的唯一标识句柄;其成员是一个整型数 fd 和一个原子计数器 AtomicInteger useCount ; 标准输入流 System.in.fd = 0 , 标准输出流 System.out.fd = 1 , 标准错误流 System.err.fd = 2

  • 文件访问权限 FilePermission: 提供了【文件可进行的操作 actions 与位掩码表示 mask 】之间的转化方法。文件可进行的操作 actions 在类 SecurityConstants 的常量中定义; mask 是一个整型数,表示文件的执行(0x01)/写(0x02)/读(0x04)/删(0x08)/读链接(0x10)/无(0x00) 等权限组合。

  • FileSystem:所使用的操作系统平台的文件系统。指明该文件系统所使用的【文件分隔符、路径分隔符、路径标准化、路径解析、文件访问安全控制、文件元信息访问、文件操作等】。文件分割符是指路径名中分割目录的符号,linux = '/', windows = '\' ; 路径分割符是环境变量中分割多个路径的符号,linux = ':' , windows = ';' ; UnixFileSystem 提供了 FileSystem 的一个实现示例。

  • 枚举: 存在 BA_EXISTS = 0x01; 普通文件 BA_REGULAR = 0x02; 目录 BA_DIRECTORY = 0x04; 隐藏 BA_HIDDEN = 0x08; 可读 ACCESS_READ = 0x04; 可写 ACCESS_WRITE = 0x02; 可执行 ACCESS_EXECUTE = 0x01; 判断文件属性及访问权限采用与或非位运算实现, 优点是可以灵活组合。

序列化

  • 序列化是实现内存数据持久化的机制。可以将 Java 对象数据存储到文件中,或者将文件中的数据恢复成Java对象。Java RPC, Dubbo,ORM 等都依赖于序列化机制。

  • 序列化相关的类及方法: Serializable/Externalizable, ObjectInputStream, ObjectOutputStream, readObject, writeObject 。

  • 使用 ObjectInputStream.readObject, ObjectOutputStream.writeObject 方法进行对象序列化: JDK提供的标准对象序列化方式;对象必须实现 Serializable 接口;适用于任何 Java 对象图的序列化,通用的序列化方案;输出为可读性差的二进制文件格式,很难为人所读懂,无法进行编辑;对某些依赖于底层实现的组件,存在版本兼容和可移植性问题;只有基于 Java 的应用程序可以访问序列化数据;
  • 使用 XMLDecoder.readObject, XMLEncoder.writeObject 方法进行对象序列化: 对象是普通的 javaBean,无需实现 Serializable 接口;输出为可读性良好的XML文件,容易编辑和二次处理;其它平台亦可访问序列化数据;可以修改数据成员的内部结构的实现,只要保留原有bean属性及setter/getter签名,就不影响序列化和反序列化;可以解决版本兼容的问题,提供长期持久化的能力;每个需要持久化的数据成员都必须有一个 Java bean 属性。
  • 实现 Externalizable 接口来进行对象序列化。需在对象中实现 readObject, writeObject 方法,提供更高的序列化灵活性,由开发者自行决定实例化哪些字段、何种顺序、输出格式等细节。

NewIO

  • java.nio 为 javaIO 体系引入了更好的性能改善,主要是 Buffer, Channel 和 file 相关的支撑类。由于 java.io 类已经引用了 nio 里的类,因此直接使用 java.io 里的类就可以获得 nio 带来的好处了。

  • nio后续再完善。

代码阅读小记

  • 理解框架的关键在于理清其设计思路及概念结构(概念及其关联)。

  • 阅读 JDK 代码可以获得很多面向对象的软件框架设计的有益启示。

javaIO框架小析的更多相关文章

  1. gtest运行小析

    Gtest是google推出的C++测试框架,本篇文档,从整体上对Gtest的运行过程中的关键路径进行分析和梳理. 分析入口 新建一个最简单的测试工程,取名为source_analyse_proj,建 ...

  2. Poco logger 日志使用小析

    Poco logger 日志使用小析 Poco logger 日志使用小析 日志 logger 库选择 Pocologger 架构简析 步骤一 生成消息 步骤二 写入logger 步骤三 导入chan ...

  3. PHP单一文件入口框架简析

    <?php /** * PHP单一文件框架设计简析 * 1.MVC架构实现 * 2.URL路由原理 */ //URL路由原理 /** * 路由作用 * 获取url中的c和a变量,执行c类对应的方 ...

  4. JDK框架简析--java.lang包中的基础类库、基础数据类型

    题记 JDK.Java Development Kit. 我们必须先认识到,JDK不过,不过一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含 ...

  5. js回调函数,字符串,数组小析

    (一)回调函数:是指通过函数参数传递到其他代码的,某一块可执行代码的引用.这一设计允许了底层代码调用在高层定义的子程序.在抖动函数中,回调函数用于在实现一些功能之后采取的另外的措施,比如div,照片抖 ...

  6. ArcGIS Earth数据小析

    ArcGIS Earth,一款轻量级的三维地球应用.因为工作关系下载试用了半天,正好借这个机会简单研究一下ArcGIS Earth的大概思路,特别是地形数据的组成和影像数据的加载,在这总结整理一下.下 ...

  7. Android Hook Dexposed原理小析

    dexposed是阿里巴巴在xposed框架上面开发的hotpatch一套框架 当然hotpatch的方式有很多,这里先介绍下dexposed原理 Demo中有个test函数, 在调用hook之前正常 ...

  8. [Node.js] ECMAScript 6中的生成器及koa小析

    原文地址:http://www.moye.me/2014/11/10/ecmascript-6-generator/ 引子 老听人说 koa大法好,这两天我也赶了把时髦:用 n 安上了node 0.1 ...

  9. android动画小析

    这里所讲的动画,是android framework提供的动画框架里面的动画. 是view层级的动画.不涉及到底层opengl es相关的动画实现. 动画: 主要包括 Interpolation du ...

随机推荐

  1. Debug与Release的区别

    Debug版本包括调试信息,所以要比Release版本大很多(可能大数百K至数M).至于是否需要DLL支持,主要看你采用的编译选项.如果是基于ATL的,则Debug和Release版本对DLL的要求差 ...

  2. 单例 (JAVA)

    java中单例模式是一种常见的设计模式,以下是它的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例 第一种(懒汉,线程不安全):  1 publ ...

  3. [LintCode] Simplify Path 简化路径

    Given an absolute path for a file (Unix-style), simplify it. Have you met this question in a real in ...

  4. Linux_文件及文件夹[创建][复制][移动][删除][重命名]

    一.文件/文件夹创建 1.文件的创建 touch , vi/vim/nano , ... 语   法: touch [-acfm][-d <日期时间>][-r <参考文件或目 录&g ...

  5. Lrucache缓存技术

    在Android中,有一个叫做LruCache类专门用来做图片缓存处理的. 它有一个特点,当缓存的图片达到了预先设定的值的时候,那么近期使用次数最少的图片就会被回收掉. 步骤: (1)要先设置缓存图片 ...

  6. html使用心得

    (1)<textarea style= "word-break:break-all" rows="5" cols="20"> 在 ...

  7. HTML5初学篇章_4

    HTML5的表单所有type类型(补第一章) 类型 说明 button 定义可点击的按钮(大多与 JavaScript 使用来启动脚本) checkbox 定义复选框. color 定义拾色器. da ...

  8. JSP中乱码问题

    一.JSP页面显示乱码 二.表单提交中文时出现乱码 三.数据库连接 大家在JSP的开发过程中,经常出现中文乱码的问题,可能一至困扰着您,我现在把我在JSP开发中遇到的中文乱码的问题及解决办法写出来供大 ...

  9. 你应了解的4种JS设计模式

    学习地址: http://mp.weixin.qq.com/s?__biz=MjM5MTA1MjAxMQ==&mid=2651223556&idx=1&sn=8cd7a2272 ...

  10. 关于Response.redirect()方法

    1. sendRedirect 后面要加上return.2. sendRedirect 执行过程是先转向还是先执行后续代码再转向?答: 先执行代码再转向,在一个sendRedirect后面不能再有其他 ...