Java I/O
2024-4-6
| 2024-9-2
0  |  Read Time 0 min
type
status
date
slug
summary
tags
category
icon
password

前言

Java I/O(Input/Output)是 Java 编程语言中用于处理输入和输出操作的一组 API。在 Java 中,I/O 操作是通过流(Stream)的方式进行的,流是用于在程序和外部源(文件、网络连接、内存等)之间传输数据的抽象。

Java I/O 基础

Java IO库提供了各种类和接口,用于处理文件、网络连接、内存等不同来源的数据输入和输出。下图展示常用的 java.io 包中的类和他们的继承关系:
notion image
Java类库中的 I/O 类分成输入和输出两部分,InputstreamReader 派生而来的类都含有名为 read() 的基本方法,OutputStreamWriter 派生而来的类都含有名为 write() 的基本方法。但是,我们通常不会用到这些方法,他们之所以存在是因为别的类可以使用他们,以便提供更有用的接口。因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能(这是装饰器设计模式)。

InputStream 类型

InputStream 的作用是用来表示那些从不同数据源产生输入的类。这些数据源包括:
  • 字节数组
  • String 对象
  • 文件
  • “管道”,工作方式与实际管道相似,即从一端输入,从另一端输出
  • 一个由其他种类的流组成的序列,以便我们可以将他们手机合并到一个流内
  • 其他数据源,如 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类提供有用功能。

OutputStream 类型

该类别的类决定了输入要去往的目标:字节数组(但不是 String,不过可以用字节数组自己创建)、文件或管道。另外,FilterOutputStream 为“装饰器”类提供了一个基类,“装饰器”类把属性或者有用的接口与输出流连接了起来。
功能
构造器参数
如何使用
ByteArrayOutputStream
在内存中创建缓冲区。所有送往“流”的数据都要放置在此缓冲区
缓存区初始化尺寸(可选的)
用于指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
FileOutputStream
用于将信息写至文件
字符串,表示文件名、文件或FileDescriptor对象
指定数据的目的地:将其与FilterOutputStream对象相连以提供有用的接口
PipedOutputStream
任何写入其中的信息都会自动作为相关PipedInputStream 的输出。实现管道化概念
PipedInputStream
指定用于多线程的数据的目的地:将其与FilterOutputStream对象相连以提供有用接口
FilterOutputStream
抽象类,作为装饰器的接口。其中装饰器为其他OutputStream提供有用功能。
因为 I/O 流的这些类功能具有对称性,这里就不再一一描述,详细信息可参加《Java 编程思想》。
下面通过几个示例展示这些类常见用法:
  • 从文件中读取,字节流
  • 写入文件,字节流
  • 读取文件,字符流

装饰器模式的应用

下面示例演示 Java I/O 中装饰器模式的应用:
DataOutputStream、BufferedOutputStream 是 FilterOutputStream 的子类,FilterOutputStream、FileOutputStream 是 OutputStream 的子类,为了向文件中写入数据,首先需要创建一个 FileOutputStream,提升访问的效率,将它发送给具备缓存功能的 BufferedOutputStream,而为了实现与机器类型无关的 java 基本类型数据的输出,我们将缓存的流传递给了 DataOutputStream。从上面的关系不难看出,这些类都是在为 OutputStream 添加额外的功能。而这种额外功能的添加就是采用了装饰模式。
请注意,在实际开发中,使用 DataOutputStream 写入数据时,需要确保读取数据的程序能够正确解析这些数据。通常情况下,读取数据时需要使用 DataInputStream 来读取相同类型的数据,以确保正确的数据类型匹配。

字节流 vs 字符流

在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
如果要 java 程序实现一个拷贝功能,应该选用字节流进行操作(可能拷贝的是图片),并且采用边读边写的方式(节省内存)。
通常可以根据具体需求来选择使用字节流还是字符流。这取决于你处理的数据类型以及对性能和编码的需求。
使用字节流(Byte Streams)
  1. 处理二进制数据:如果你需要处理图片、音频、视频等二进制数据,应该使用字节流。字节流可以直接处理字节数据,适合于二进制数据的读写操作。
  1. 性能要求高:字节流通常比字符流更高效,因为它们直接操作字节而不涉及字符编码转换。
  1. 不需要进行字符编码转换:如果处理的数据不需要进行字符编码转换,例如在网络传输或文件复制过程中,字节流是更合适的选择。
使用字符流(Character Streams)
  1. 处理文本数据:如果你需要处理文本数据,例如读取文本文件内容或向文件中写入文本数据,应该使用字符流。字符流会处理字符编码,确保正确地读写文本数据。
  1. 需要进行字符编码转换:如果需要在不同字符编码之间进行转换,例如从 UTF-8 转换为 UTF-16,字符流会更方便。
  1. 方便处理文本数据:字符流提供了更高级的功能,如 BufferedReader 和 BufferedWriter,可以方便地处理文本数据的读写操作。
在实际开发中,根据具体场景来选择合适的流。如果处理的是文本数据,字符流可能更适合;如果处理的是二进制数据,字节流可能更合适。有时候也可以结合使用,比如使用字符流读取文本文件内容,然后使用字节流将数据写入网络连接。

参考文档

《Java 编程思想》
 
Feature
NIO (New I/O)
序列化
字符集
 
CMake 安装C++ 程序编译流程
  • Utterance
Catalog