Table of Contents

  1. 前言
  2. 字节流
    1. 常用实现
  3. 字符流
    1. 常用实现
  4. 缓冲区
  5. 各种字节流
  6. 结语

前言

由于在接触 Java 之前使用的语言是 Python,所以在转到 Java 后对 Java 的 I/O 操作各种不习惯。

研究后发现 Java 的 I/O 模型和 Python 的基本上还是一样的,只是在接口的设计上有些区别,主要是为了符合 OOP 的思想吧。

这篇博客的主要内容便是和 Java I/O 相关的总结。

字节流

和 Python 一样,Java 中最底层的 I/O 接口处理的是 字节序列, 但是和 Python 中的文件对象一把梭不一样,Java 将输入和输出分别抽象为了两个对象。

处理输入流的 InputStream 和处理输出流的 OutputStream.

这两个类都是抽象类,因此具体的和输入输出相关的功能将由它们的子类实现,而它们则提供一些基本的接口:

  • InputStream 提供的部分接口:

    方法 作用
    abstract int read() 读取一个字节,碰到输入流结尾时返回 -1
    int read(byte[] b) 将数据读入提供的字节数组,并返回实际读入的字节数,或者在碰到输入流结尾时返回 -1
    int read(byte[] b, int off, int len) 将数据读入提供的字节数组,并返回实际读入的字节数,或者在碰到输入流结尾时返回 -1,写入的范围由 off 和 len 指定
  • OutputStream 提供的部分接口:

    方法 作用
    abstract void write() 写入一个字节的数据
    void write(byte[] b) 写入一个字节数组的数据
    void write(byte[] b, int off, int len) 写入字节数组的数据,数据范围由 off 和 len 指定
    void flush() 将缓存的数据全部写入目标

可以看到,抽象方法其实只有 read()write(), 其他的方法会调用这两个方法,因此子类只需要提供这两个抽象方法的实现就可以了。

常用实现

Java 中字节流的具体实现很多,但最常用的应该就是和 文件 相关的了,因此在这里将它们列举出来:

  • FileInputStream 的构造方法:

    构造方法 说明
    FileInputStream(FileDescriptor fdObj) 根据指定的文件描述符创建输入流
    FileInputStream(File file) 根据指定的文件对象创建输入流
    FileInputStream(String name) 根据指定的文件名称创建输入流
  • FileOutputStream 的构造方法和 FileInputStream 的基本相同,不同的是多了两个存在布尔标志的构造方法:

    构造方法 说明
    FileOutputStream(File file, boolean append) 根据指定的文件对象创建输出流,布尔标志指定是否追加
    FileOutputStream(String name, boolean append) 根据指定的文件名称创建输出流,布尔标志指定是否追加

在之前学习 C 和 Python 的过程中便了解到 文件描述符 是一个很有用的东西,通过它可以实现一些很有用的功能。

在 Java 中获取文件描述符可以通过调用 FileInputStreamFileOutputStream 对象的 getFD() 方法完成,而标准输入输出的文件描述符则需要通过 FileDescriptor 的静态字段获取。

字符流

通过字节流可以完成很多 I/O 操作,但是如果连文本文件的处理都通过字节流来完成的话就太麻烦了。因此,为了解决这样的问题,

字符流便诞生了。

字符流 是对 字节流 的一层封装,在 Java 中通过 ReaderWriter 这两个抽象类来表示。

和 InputStream 和 OutputStream 一样,具体的功能将由它们的子类实现,而它们则提供一些基本的接口,这里列举出最基本的接口:

  • Reader:

    方法 作用
    int read() 读取单个字符,返回值是该字符的码点,到达流的末尾就返回 -1
  • Writer:

    方法 作用
    void write(int c) 写入单个字符
    void write(String str) 写入字符串
    abstract void flush() 将缓存的数据全部写入目标

需要注意的是,这里的 read() 方法和 write() 都不是抽象方法了,因为这两个方法实际上都是调用内部的 字节流 完成工作,因此,只需要相应的字节流实现基本的功能就足够了。

常用实现

Java 字符流实现中最常用的应该是 InputStreamReaderOutputStreamWriter 了,它们的构造方法如下:

Reader 构造方法 Writer 构造方法 说明
InputStreamReader(InputStream in) OutputStreamWriter(OutputStream out) 根据默认编码创建字符流
InputStreamReader(InputStream in, Charset cs) OutputStreamWriter(OutputStream out, Charset cs) 根据指定字符集创建字符流
InputStreamReader(InputStream in, CharsetDecoder dec) OutputStreamWriter(OutputStream out, CharsetEncoder dec) 根据指定字符集解/编码器创建字符流
InputStreamReader(InputStream in, String charsetName) OutputStreamWriter(OutputStream out, String charsetName) 根据指定字符集名称创建字符流

同时,针对文件操作,Java 提供了这两个类的子类 FileReaderFileWriter, 使用这两个类可以省略手动创建字节流的过程,具体内容可以查看相关文档。

缓冲区

I/O 操作的一个常识:频繁的 I/O 操作的效率是很低的,所以我们加一个缓冲区吧!

Java 中我们可以通过 BufferedInputStreamBufferedOutputStream 为字节流添加缓冲区,通过 BufferedReaderBufferedWriter 为字符流添加缓冲区。

这样一来,一段经典的代码就成型了:

// 字节流 -> 字符流 -> 缓冲区
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("example.txt")));

很完美是不是!

各种字节流

虽然说最常用的字节流式文件字节流(大概),但是,输入输出的环境是复杂的,处理文件以外,其他的设备如内存、网络等都可能用到输入输出,

而且不同的条件下需要的功能还不一样。

字符流的需求相对来说较为统一,因此一般情况下 InputStreamReaderOutputStreamWriter 完全可以一统天下,但是对于 字节流 来说,Java 提供了各种各样的实现。

尤其是 FilterInputStreamFilterOutputStream 的子类,它们都有以输出/输出流作为参数的构造方法,因此,我们可以将不同的 Filter 组装起来,得到我们想要的功能。

这是除了 字节-字符-缓冲 以外让我觉得最 Beautiful 的设计,能够灵活的适应各种需求。

这些 Filter 的使用可以查看官方文档或者看看《Java 核心技术卷卷二》的 2.1.3 节,这是相当棒的功能。

结语

写完博客回头看,感觉质量有点差……

篇幅太少了,很多东西都没有说清楚,属于适合自己回顾的博客 @_@

另外,很想吐槽的是:作为面向对象的语言,Java 内置的网络库居然没有将 请求响应 这两个对象分开!!!

用起来各种不顺手……

Java 中的 I/O 抽象的更多相关文章

  1. java中的输入输出<1>

    java中的输入输出基础(1) java中的IO支持通过java.io包下的类和接口来支持.在java.io包下主要包括输入.输出两种io流,每种输入.输出流又分为字节流和字符流. 字节流就是以字节为 ...

  2. java学习(九) —— java中的File文件操作及IO流概述

    前言 流是干什么的:为了永久性的保存数据. IO流用来处理设备之间的数据传输(上传和下载文件) java对数据的操作是通过流的方式. java用于操作流的对象都在IO包中. java IO系统的学习, ...

  3. Java中的继承、封装、多态、抽象

    1.继承 java 和某些面向对象语言(如 c++)在实现继承的不同之处在于java只支持单继承,不支持多重继承.即java 中一个类只能继承于另一个类.我们将被继承的类称之为父类(基类),继承类称之 ...

  4. 理解Java中的抽象

    在计算机科学中,抽象是一种过程,在这个过程中,数据和程序定义的形式与代表的内涵语言相似,同时隐藏了实现细节. 抽象:一个概念或者想法不和任何特定的具体实例绑死. 目录 什么是抽象 抽象的形式 如何在J ...

  5. 【转载】JAVA中综合接口和抽象类实现的一种“抽象接口”

    Muscleape个人总结:(这里的抽象接口是指:使用一个抽象类实现一个接口,是两部分结构) 使用一个抽象类直接实现接口,将接口中的方法区分为实现类必须要实现的和选择性实现的,其他需要实现接口的类型通 ...

  6. Java中的抽象和封装

    一.面向对象和面向过程的区别 面向对象: 核心:封装了属性和方法的类,以数据为中心,实现了类级别的代码重用 面向对象因为采用了类,所以具有继承和多态特性,可以进一步重用代码和简化编程 面向过程: 核心 ...

  7. java中静态,抽象,接口,继承总结

    (一).静态: 1.静态方法里只能访问静态变量,静态变量是类所特有的,所有类实例都作用同一个变量 静态随着类的加载而加载 (二). 抽象:抽象相当于接口,没有方法体,只定义方法,让子类实现,抽象类中可 ...

  8. java中的对象 方法 引用 等一些抽象的概念是什么意思呢?

    2020-03-14 最近这一段时间有点忙,好久都没有更新博客了,之后我会一直坚持下去的,和大家一同进步的. 这段时间一直在学java,相信刚开始学习java的小白,刚开始接触那么些抽象的概念一定和我 ...

  9. java中抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰

    1.abstract与static what abstract:用来声明抽象方法,抽象方法没有方法体,不能被直接调用,必须在子类overriding后才能使用. static:用来声明静态方法,静态方 ...

随机推荐

  1. QT学习之QScript

    QT中有解析Json的一个类叫QScript.貌似还有一个QJson,但听说解析的方便性不如QScript,具体没有深入探究,这里仅简单记录一下QScript的使用. 首先,主要使用到的类有QScri ...

  2. QT创建与调用Dll方法(包括类成员)--显式调用

    看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...

  3. TeXstudio安装后提示no LaTeX distribution found on this system

    应该是设置一下用户变量,而非系统变量,用TeXLive 2015和MikTeX都不好使,最后设置了用户变量好使了 S:\TeX\MiKTeX 2.9\miktex\bin\x64\ 也是醉醉的 不过等 ...

  4. @RequiresPermissionss是否可以填写多种权限标识,只要满足其一就可以访问?

    @RequiresPermissionss是否可以填写多种权限标识,只要满足其一就可以访问?  发布于 180天前  作者 qq_b02c4863  144 次浏览  复制  上一个帖子  下一个帖子 ...

  5. Mysql limit 优化,百万至千万级快速分页,--复合索引的引用并应用于轻量级框架

    MySql 性能到底能有多高?用了php半年多,真正如此深入的去思考这个问题还是从前天开始.有过痛苦有过绝望,到现在充满信心!MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新闻 ...

  6. Linux下内存的几个基本概念

    先介绍几个基本概念: SIZE: 进程使用的地址空间, 如果进程映射了100M的内存, 进程的地址空间将报告为100M内存. 事实上, 这个大小不是一个程序实际使用的内存数. RSS: "R ...

  7. 第22章 常用存储器介绍—零死角玩转STM32-F429系列

    第22章     常用存储器介绍 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...

  8. python 多进程,多线程,协程

    在我们实际编码中,会遇到一些并行的任务,因为单个任务无法最大限度的使用计算机资源.使用并行任务,可以提高代码效率,最大限度的发挥计算机的性能.python实现并行任务可以有多进程,多线程,协程等方式. ...

  9. iOS 远程通知(Remote Notification)和本地通知(Local Notification)

    ios通知分为远程通知和本地通知,远程通知需要连接网络,本地通知是不需要的,不管用户是打开应用还是关闭应用,我们的通知都会发出,并被客户端收到 我们使用远程通知主要是随时更新最新的数据给用户,使用本地 ...

  10. vue-router 实现分析

    我们分别从不同的视角来看 vue-router. http://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=2247485737&idx ...