java 17 的 I/O 基础 OutputStream 篇
接下来再来看看 OutputStream 以及子类的相关使用。
对于 OutputStream 主要是字节流类型的输出流。
OutputStream
OutputStream 抽象类是所有字节输出流类的超类。输出流接受输出字节并将它们发送到某个接收器中。 同样该抽象类需要一个子类来继承实现始终提供至少一种写入一个字节输出的方法。
该类的定义:
public abstract class OutputStream implements Closeable, Flushable
抽象类 中的方法包括:
从本篇开始尽量使用表格而不使用图片,因为我发现复看我的文章的时候,图片的清晰度真不能看。
修饰符和类型 | 方法 | 描述 |
void | close() | 关闭此输出流并释放与此流关联的所有系统资源。 |
void | flush() | 刷新此输出流并强制写出任何缓冲的输出字节。 |
static OutputStream | nullOutputStream() | 返回一个丢弃所有字节的新 OutputStream。 |
void | write( byte [] b) | 将指定字节数组中的 b.length 个字节写入此输出流。 |
void | write(byte[] b, int off, int len) | 将指定字节数组中的 len 个字节写入此输出流。 |
abstract void | write(int b) | 将指定字节写入此输出流。 |
因为是抽象类,并不能真正的进行操作,只有子类才能执行,接下来我们来看看子类具体实现。
子类实现
ByteArrayOutputStream
这个类实现了一个输出流,其中数据被写入一个字节数组。 缓冲区会随着数据写入而自动增长。 可以使用 toByteArray() 和 toString () 检索数据。 关闭 ByteArrayOutputStream 无效。 可以在流关闭后调用此类中的方法,而不会生成 IOException。
定义:
public class ByteArrayOutputStream extends OutputStream
方法的定义:
演示使用小例子
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
for (byte i =; i < 10; i++) {
byteArrayOutputStream.write(i);
}
System.out.println("byteArrayOutputStream.size(): " + byteArrayOutputStream.size());
byte[] array = byteArrayOutputStream.toByteArray();
for (byte b : array) {
System.out.print(b + "t");
}
} catch (IO Exception ex) {
System.out.println(ex.getMessage());
}
完整代码及运行
FileOutputStream
文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或是否可以创建取决于底层平台。特别是某些平台,一次只允许一个 FileOutputStream (或其他文件写入对象)打开一个文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的 构造函数 将失败。 FileOutputStream 用于写入原始字节流,例如图像数据。要写入字符流,请考虑使用 File write r。
定义:
public class FileOutputStream extends OutputStream
该类的构造函数:
构造器 | 描述信息 |
FileOutputStream(File file) | 创建一个文件输出流以写入由指定 File 对象表示的文件。 |
FileOutputStream(FileDescriptor fdObj) | 创建一个文件输出流以写入指定的文件描述符,它表示与文件系统中实际文件的现有连接。 |
FileOutputStream(File file, boolean append) | 创建一个文件输出流以写入由指定 File 对象表示的文件。 |
FileOutputStream(String name) | 创建文件输出流以写入具有指定名称的文件。 |
FileOutputStream(String name, boolean append) | 创建文件输出流以写入具有指定名称的文件。 |
对于子类的方法, 除了父类的方法外,又新增了两个方法。新增方法如下:
修饰符和类型 | 方法 | 描述 |
FileChannel | getChannel() | 刷新此输出流并强制写出任何缓冲的输出字节。 |
final FileDescriptor | getFD() | 返回一个丢弃所有字节的新 OutputStream。 |
并重写了 close, write的三个方法。
查看代码:
String content = "把该段内容写入到文件系统中。";
byte[] bytes = content.getBytes();
try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt")) {
fileOutputStream.write(bytes);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
演示案例:
这里需要注意的是,文件的写入默认使用和系统相关的 字符集 , 我这是中文的系统,默认情况下是 GBK 的字符集体系。所以要看你的情况来选择, 后续写到 Writer 之后,在说字符集转换的问题。还有 cat 命令。这个命令只有在 PowerShell 的命令行工具中存在, cmd 命令行中并没有该指令。
另外的使用方式如下:
new FileOutputStream(new File("file.txt"));
new FileOutputStream(new File("file.txt"), true);
new FileOutputStream("file.txt", true)
完整代码如下:
运行效果,后面两个都是追加数据的意思,保留原先的数据写入:
FilterOutputStream
这个类是过滤输出流的所有类的超类。 这些流位于已经存在的输出流(底层输出流)之上,它用作其基本数据接收器,但可能会沿途转换数据或提供附加功能。 FilterOutputStream 类本身只是简单地使用将所有请求传递到底层输出流的版本覆盖了 OutputStream 的所有方法。 FilterOutputStream 的子类可能会进一步覆盖其中一些方法,并提供额外的封装方法和需要的字段。
定义:
public class FilterOutputStream extends OutputStream
该类只有一个构造函数, 构造方法 为:
构造函数 | 描述信息 |
FilterOutputStream(OutputStream out) | 在指定的基础输出流之上创建一个输出流过滤器。 |
查看代码案例:
String content = "使用 FilterOutputStream 把该段内容写入到文件系统中。";
byte[] bytes = content.getBytes();
try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt");
FilterOutputStream filterOutputStream = new FilterOutputStream(fileOutputStream)) {
filterOutputStream.write(bytes);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
完整代码及运行效果:
ObjectOutputStream
ObjectOutputStream 将 Java 对象的原始数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。对象的持久存储可以通过使用流的文件来实现。如果流是网络套接字流,则可以在另一个主机或另一个进程中重构对象。
只有支持 java.io.Serializable 接口的对象才能写入流。每个可序列化对象的类都经过编码,包括类的类名和签名、对象的字段和数组的值,以及从初始对象引用的任何其他对象的 闭包 。 writeObject 方法用于将对象写入流。任何对象,包括 字符串 和数组,都是用 writeObject 编写的。可以将多个对象或原语写入流。对象必须从相应的 ObjectInputstream 以与写入时相同的类型和相同的顺序读回。
定义为:
public class ObjectOutputStream
extends OutputStream implements ObjectOutput, ObjectStreamConstants
对应的构造方法如下:
构造函数 | 描述说明 |
ObjectOutputStream() | 为完全重新实现 ObjectOutputStream 的子类提供一种方法,使其不必分配刚刚由 ObjectOutputStream 的实现使用的私有数据。 |
ObjectOutputStream(OutputStream out) | 创建一个写入指定 OutputStream 的 ObjectOutputStream。 |
直接代码演示:
可以使用 ObjectInputStream 输入流读取对应的序列化内容。
常用的 write 方法
代码:
String str = "使用序列化进行字符串的写入";
try (FileOutputStream fileOutputStream = new FileOutputStream("string.tmp");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
objectOutputStream.writeObject(str);
objectOutputStream.writeByte();
objectOutputStream.writeChar();
objectOutputStream.writeInt();
objectOutputStream.writeShort();
objectOutputStream.writeFloat(.111f);
objectOutputStream.writeDouble(.11d);
objectOutputStream.writeLong(L);
objectOutputStream.writeBoolean(true);
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
PipedOutputStream
管道输出流可以连接到管道输入流以创建通信管道。 管道输出流是管道的发送端。 通常,数据由一个 线程 写入 PipedOutputStream 对象,数据由其他线程从连接的 Piped InputStream 读取。 不建议尝试从单个线程中使用这两个对象,因为它可能会使线程死锁。 如果从连接的管道输入流中读取数据字节的线程不再活动,则称该管道已损坏。
定义:
public class PipedOutputStream extends OutputStream
构造函数
构造函数 | 描述说明 |
PipedOutputStream() | 创建尚未连接到管道输入流的管道输出流。 |
PipedOutputStream(PipedInputStream snk) | 创建连接到指定管道输入流的管道输出流。 |
使用例子:
BufferedOutputStream
该类实现了一个缓冲的输出流。 通过设置这样的输出流,应用程序可以将字节写入底层输出流,而不必为每个写入的字节调用底层系统。
定义:
public class BufferedOutputStream extends FilterOutputStream
构造函数:
构造器 | 描述信息 |
BufferedOutputStream(OutputStream out) | 创建一个新的缓冲输出流以将数据写入指定的基础输出流。 |
BufferedOutputStream(OutputStream out, int size) | 创建一个新的缓冲输出流,以将数据写入具有指定缓冲区大小的指定基础输出流。 |
代码示例:
CheckedOutputStream
一个输出流,它还维护正在写入的数据的校验和。 然后可以使用校验和来验证输出数据的完整性。
定义:
public class CheckedOutputStream extends FilterOutputStream
同样只有一个构造函数
构造器 | 描述信息 |
CheckedOutputStream(OutputStream out, Checksum cksum) | 创建具有指定校验和的输出流。 |
方法有一个父类没有的方法 getChecksum() 意思是:返回此输出流的校验和。
演示代码:
try (FileOutputStream fos = new FileOutputStream("file.txt");
CheckedOutputStream check = new CheckedOutputStream(fos, new CRC());) {
String content = "这个是 CheckedOutputStream 写入的内容";
byte[] array = content.getBytes();
for (byte b : array) {
check.write(b);
}
long ckSum = check.getChecksum().getValue();
System.out.println("Checksum:x" + Long.toHexString(ckSum).toUpperCase());
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
完整代码和运行效果:
使用工具校验一下 CRC32 的校验码是否一致。
CipherOutputStream 不在演示,在加密和解密知识点在来详细说这个。
DataOutputStream
数据输出流允许应用程序以可移植的方式将原始 Java 数据类型写入输出流。 然后,应用程序可以使用数据输入流来读回数据。 多个并发线程使用 DataOutputStream 是不安全的。 如果一个 DataOutputStream 被多个线程使用,那么对数据输出流的访问应该由适当的同步控制。
定义:
public class DataOutputStream extends FilterOutputStream implements DataOutput
代码演示效果:
try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt");
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream)) {
String content = "这个是 DataOutputStream 的演示";
byte[] array = content.getBytes();
for (byte b : array) {
dataOutputStream.write(b);
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
对于 DeflaterOutputStream 和 InflaterOutputStream 是压缩和解压的输出流。这里先不做演示。
PrintStream
PrintStream 向另一个输出流添加了功能,即能够方便地打印各种数据值的表示形式。
还提供了另外两个功能。与其他输出流不同,PrintStream 从不抛出 IOException;相反,异常情况只是设置一个内部标志,可以通过 checkError 方法进行测试。
也可以可选的创建一个 PrintStream 以便自动刷新;这意味着在写入字节数组、调用 println 方法之一或写入换行符或字节 (‘n’) 后,会自动调用底层输出流的 flush 方法。
PrintStream 打印的所有字符都使用给定的编码或字符集转换为字节,如果未指定,则使用平台的默认 字符编码 。 PrintWriter 类应该用于需要写入字符而不是字节的情况。 这个类总是用字符集的默认替换字符串替换格式错误和不可映射的字符序列。
当需要对 编码 过程进行更多控制时,应使用 Charset Encoder 类。
演示代码:
这里来看我们经常用到的一个使用方法。
System.out.println("输出一串字符串。");
该类是 System
java.lang .System
public final class System
里面有个静态的常量方法 out 返回值是: PrintStream。 然后就可以理解为什么可以打印字符串了。
所以 System.out.println(“”); 基本等同于 new PrintStream(“file.txt”).println(“”); 区别是一个输出到了控制台, 一个输出到了文件中。 这也是以后在 web 开发中使用 System.out 打印信息的时候, 其实也会写到日志文件中一样。
OutputStream 相关的知识点就先说到这了。 应该把相关的案例使用都介绍到了, 如果没有提到,希望评论区中说出来, 共同学习。感谢。
点赞,收藏,关注。持续更新全栈的知识点。持续的输出原创且有思考的内容。