java编程思想-IO总结

一、输入和输出

编程语言的I/O类库中常使用这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。

Java类库中的I/O类分成输入和输出两部分。通过继承,任何自Inputstream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写单个字节或字节数组。但是,我们通常不会用到这些方法,他们之所以存在是因为别的类可以使用他们,以便提供更有用的接口。因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能(这是装饰器设计模式)。实际上,Java中“流”类库让人迷惑的主要原因在于:创建单一的结果流,却需要创建多个对象。

1、InputStream类型

InputStream的作用是用来表示那些从不同数据源产生输入的类。这些数据源包括:

  • 字节数组
  • String对象
  • 文件
  • “管道”,工作方式yu与实际管道相似,即从一端输入,从另一端输出。
  • 一个由其他种类的流组成的序列,以便我们可以将他们手机合并到一个流内。
  • 其他数据源,如Internet连接等。

每一种数据源都有相应的InputStream子类。另外,FilterInputStream也属于一种InputStream,为“装饰器(decorator)”类提供积累。其中,“装饰器”类可以把属性或有用的接口与输入流连接在一起。

功能 构造器参数和如何使用
ByteArrayInputStream 允许将内存的缓冲区当做inputStream使用 缓冲区,字节将从中取出;作为一种数据源:将其与FilterInputStream对象相连以提供有用接口
StringBufferInputStream 将String转换成InputStream 字符串。底层实现实际使用StringBuffer;作为一种数据源:将其与FilterInputStream对象相连以提供有用接口
FileInputStream 用于从文件中读取信息 字符串,表示文件名、文件或FileDescriptor对象;作为一种数据源:将其与FilterInputStream对象相连以提供有用接口
PipedInputStream 产生用于写入相关PipedOutputStream的数据。实现管道化概念 PipedOutputStream;作为多线程中的数据源:将其与FilterInputStream对象相连以提供有用接口
SequenceInputStream 将两个或多个InputStream对象转换成单一InputStream 两个InputStream对象或一个容纳InputStream对象的容器Enumeration;作为一种数据源:将其与FilterInputStream对象相连以提供有用接口
FilterInputStream 抽象类,作为“装饰器”的接口。其中装饰器为其他的InputStream类提供有用功能。 见下表

2、OutputStream类型

该类别的类决定了输入要去往的目标:字节数组(但不是String,不过可以用字节数组自己创建)、文件或管道。

另外,FilterOutputStream为“装饰器”类提供了一个基类,“装饰器”类把属性或者有用的接口与输出流连接了起来。

功能 构造器参数 如何使用
ByteArrayOutputStream 在内存中创建缓冲区。所有送往“流”的数据都要放置在此缓冲区 缓存区初始化尺寸(可选的) 用于指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
FileOutputStream 用于将信息写至文件 字符串,表示文件名、文件或FileDescriptor对象 指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
PipedOutputStream 任何写入其中的信息dou'h都会自动作为相关PipedInputStream的输出。实现管道化概念 PipedInputStream 指定用于多线程的数据的目的地:将其与FilterOutputStream对象相连以提供有用接口
FilterOutputStream 抽象类,作为装饰器的接口。其中装饰器为其他OutputStream提供有用功能。 见下表 见下表

二、Reader和Writer

尽管一些原始的“流”类库不再被使用,但是InputStream和OutputStream在以面向字节形式的I/O中仍可以提供极有价值的功能,Reader和Writer则提供兼容Unicode与面向字符的I/O功能。另外:

  • Java1.1向InputStream和OutputStream继承层次结构中添加了一些新类,所以显然这两个类是不会被取代的。
  • 有时我们必须把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。为了实现这个目的,要用到“适配器”类:InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。

设计Reader和Writer继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符。由于Unicode用于字符国际化(java本身的char也是16位的Unicode),所以添加Reader和Writer继承层次结构就是为了在所有的I/O操作中都支持unicode。另外,新类库的设计使得它的操作比旧类库更快。

三、新I/O:NIO

速度的提高来自于所使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。我们可以把它想象成一个煤矿,通常是一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。卡车满载煤炭而归,我们从卡车上获得煤炭。也就是我们没有和通道直接交互,我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么从缓冲器获得数据,要么向缓冲器发送数据。

唯一直接与通道交互的缓冲器是ByteBuffer--也就是说,可以存储未加工字节的缓冲器。当我们查询JDK文档中的java.nio.ByteBuffer时,会发现他是相当基础的类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用于以原始的字节形式或基本数据类型输出和读取数据。但是,没办法输出或读取对象,即使是字符串对象也不行。这种处理虽然很低级,但却正好,因为这是大多数操作系统中更有效的映射方式。

旧I/O类库中有三个类被修改了,用以产生FileChannel。这三个被修改的类是FileInputStream、FileOutputStream以及用于既读又写的RandomAccessFile。注意这些是字节操纵流,与低层的NIO性质一致。Reader和Writer这种字符模式类不能用于产生通道,但是java.nio.channels.Channels类提供了实用方法,用以在tong'dao'zho通道中产生Reader和Writer。

四、对象序列化

Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。这一过程甚至可以通过网络进行;这意味着序列化机制能够自动弥补不同操作系统之间的差异。也就是说,可以在运行windows系统的计算机上创建一个对象,将其序列化,通过网络将它发送给一台运行Unix系统的计算机,然后在那里准确的重新组装,而却不必担心数据在不同机器上的表示会不同,也不必关心字节的顺序或者其他任何细节。

就其本身来说,对象的序列化是非常有趣的,因为利用它可以实现轻量级持久性(lightweight persistence)。持久性一位置一个对象的生存周期并不取决于程序是否正在执行;他可以生存与程序的调用之间。通过j一个序列化对象写入磁盘,然后在重新调用程序时恢复该对象,就能够实现持久性的效果。之所以称其为“轻量级”,是因为不能用某种“persistent”关键字来简单的定义一个对象,并让系统自动维护其他细节。相反,对象必须在程序中显式的序列化(serialize)和反序列化(deserialize)还原。如果需要一个更严格的持久性机制,可以考虑像Hibernate之类的工具。

对象序列化的概念加入到语言中是为了支持两种主要特性。一是java的远程方法调用RMI,它使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。

再者,对Java Beans来说,对象的序列化也是必须的。使用一个Bean时,一般情况下是在设计阶段对他的状态信息进行配置。这种状态信息必须保存下来,并在程序启动时进行后期恢复;这种具体工作就是由对象序列化完成的。

只要对象实现了Serializable接口(该接口仅是一个标机接口,不包含任何方法),对象的序列化处理就会非常简单。当序列化的概念被加入到语言中时,许多标准类库发生了改变,以便具备序列化特性-其中包括所有基本数据类型的封装器,所有容器类以及许多其他的东西。甚至Class对象也可以被序列化。

要序列化一个对象,首先要创建某些OutputStream对象,然后将其封装在一个ObjectOutputStream对象内。这时,只需调用writeObject()即可将对象序列化,并将其发送给outputStream(对象序列化是基于字节的,因此要使用InputStream和OutputStream继承层次结构)。要反向进行该过程(即将一个序列还原为一个对象),需要将一个InputStream封装在ObjectInputStream内,然后调用readObject()。和往常一样,我们最后获得的是一个引用,它只想一个向上转型的Object,所以必须向下转型才能直接设置他们。

对象序列化特别聪明的一个地方是它不仅保存了对象的“全景图”,而且能追踪对象内包含的所有引用,并保存那些对象;接着又能对对象内包含的每个这样的引用进行追踪;以此类推。这种情况有时被称为“对象网”,单个对象可与之建立连接,而且它还包含了对象的引用数组以及成员对象。如果必须保持一套自己的对象序列化机制,那么维护那些可追踪到所有链接的代码可能会显得非常麻烦。然后,由于java的对象序列化似乎找不出什么缺点,所以请尽量不要自己动手,让它用优化的算法自动维护整个对象网。

五、总结

Java I/O流类库的确能满足我们的基本需求:我们可以通过控制台、文件、内存块,甚至因特网进行读写。通过继承,我们可以创建新类型的输入和输出对象。并且通过重新定义toString()方法,我们甚至可以对流接受的对象类型进行简单扩充。当我们向一个期望收到字符串的方法传送一个对象时,会自动调用toString()方法(这是java有限的自动类型转换功能)。

在I/O流类库的文档和设计中,仍留有一些没有解决的问题。I/O流类库使我们喜忧参半。它确实能做许多事情,而且具有可移植性。但是如果我们没有理解装饰器模式,那么这种设计就不是很直觉,因此在学习和传授它的过程中,需要额外的开销。而且它并不完善。

一旦我们理解了装饰器模式,并开始在某些情况下使用该类库以利用其提供的灵活性,那么你就开始从这个设计中受益了。到那个时候,为此额外多写几行代码的开销应该不至于使人觉得太麻烦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,...
    cmlong_阅读 498评论 0 4
  • 一、按字节流读取 抽象类inputStream和outputStream两个以及他们的子类 Fileinputst...
    木以行舟阅读 384评论 0 0
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,599评论 18 399
  • 那一年,你21我18 那一年,你说你喜欢我 那一年,你说会娶我会带我去世界各地 那一年,我像她们一样享受着初恋的甜...
    兔牙姑娘阅读 162评论 0 1
  • 妙矣哉,棍棍相逢,两两比肩。惜之也,其乃终岁一得焉。然其斫木为棍,植棍生根而为木。汲后土之灵气,纳皇天之雨露而为叶...
    明白的石头阅读 667评论 0 2