Guide to Java OutputStream – Java输出流指南

最后修改: 2018年 10月 9日

中文/混合/英文(键盘快捷键:t)

 

1. Overview

1.概述

In this tutorial, we’ll explore details about the Java class OutputStream. OutputStream is an abstract class. This serves as the superclass for all classes representing an output stream of bytes.

在本教程中,我们将探讨关于Java类OutputStream的细节。OutputStream是一个抽象的类。它作为所有代表字节输出流的类的超类。

We’ll examine what do these words like “output” and “stream” mean in more details as we go along.

我们将在接下来的讨论中更详细地研究 “输出 “和 “流 “这些词的含义。

2. Brief Introduction to Java IO

2.Java IO的简要介绍

OutputStream is part of the Java IO API which defines classes required to perform I/O operations in Java. These are all packaged in the java.io namespace. This is one of the core packages available in Java since version 1.0.

OutputStream是Java IO API的一部分,它定义了在Java中执行I/O操作所需的类。这些都被打包在java.io命名空间中。这是自1.0版本以来Java中可用的核心包之一。

Starting Java 1.4, we also have Java NIO packaged in the namespace java.nio which enables non-blocking input and output operations. Our focus area for this article, however, is ObjectStream as part of Java IO.

从Java 1.4开始,我们还有打包在命名空间java.nio中的Java NIO,它可以实现非阻塞的输入和输出操作。然而,本文的重点领域是作为Java IO一部分的ObjectStream

Details related to Java IO and Java NIO can be found here.

与Java IO和Java NIO有关的细节可以在这里找到。

2.1. Input and Output

2.1.输入和输出

Java IO basically provides a mechanism to read data from a source and write data to a destination. Input represents the source while output represents the destination here.

Java IO基本上提供了一种从源头读取数据并将数据写到目的地的机制。在这里,输入代表源,而输出代表目的。

These sources and destinations can be anything from Files, Pipes to Network Connections.

这些来源和目的地可以是任何东西,从文件、管道到网络连接。

2.2. Streams

2.2.溪流

Java IO provides the concept of streams which basically represents a continuous flow of data. Streams can support many different types of data like bytes, characters, objects, etc.

Java IO提供了流的概念,基本上代表了数据的连续流动。流可以支持许多不同类型的数据,如字节、字符、对象等。

Moreover, connection to a source or a destination is what a stream represents. They hence come as either InputStream or OutputStream respectively.

此外,连接到一个源头或目的地是流的代表。因此,它们分别作为InputStreamOutputStream

3. Interfaces of OutputStream

3.OutputStream的接口

OutputStream implements a bunch of interfaces which provide some distinct character to its subclasses. Let’s go through them quickly.

OutputStream实现了一堆接口,为其子类提供了一些明显的特征。让我们快速浏览一下它们。

3.1. Closeable

3.1. 可关闭

The interface Closeable provides a method called close() which handles closing a source or a destination of data. Every implementation of OutputStream must provide an implementation of this method. Here they can perform actions to release resources.

接口Closeable提供了一个名为close()的方法,该方法处理关闭数据的来源或目的地。每个OutputStream的实现必须提供该方法的实现。在这里,他们可以执行释放资源的操作。

3.2. AutoCloseable

3.2.可自动关闭

The interface AutoCloseable also provides a method called close() with similar behavior to the one in Closeable. In this case, however, the method close() is automatically called when exiting a try-with-resource block.

接口AutoCloseable也提供了一个名为close()的方法,其行为与Closeable类似。然而,在这种情况下,当退出 try-with-resource 块时,方法close()被自动调用。

More details regarding try-with-resource can be found here.

关于 try-with-resource 的更多细节可以在这里找到。

3.3. Flushable

3.3.可冲水的</em

The interface Flushable provides a method called flush() which handles flushing data to a destination.

接口Flushable提供了一个名为flush()的方法,用于处理将数据冲到目的地。

A particular implementation of OutputStream may choose to buffer previously written bytes to optimize, but a call to flush() makes it write to the destination immediately.

OutputStream的特定实现可能会选择缓冲先前写入的字节以进行优化,但是flush()的调用使其立即写入目的地

4. Methods in OutputStream

4.输出流中的方法

OutputStream has several methods which each implementing class has to implement for their respective data types.

OutputStream有几个方法,每个实现类都必须为它们各自的数据类型实现。

These are apart from close() and flush() methods that it inherits from Closeable and Flushable interfaces.

这些是除了close()flush()方法之外,它继承了CloseableFlushable接口。

4.1. write(int b)

4.1.write(int b)

We can use this method to write one specific byte to the OutputStream. Since the argument “int” comprises four bytes, as par the contract only the first low order byte is written and the remaining three high order bytes and ignored:

我们可以使用这个方法来OutputStream写一个特定的字节。由于参数 “int “包括四个字节,按照合同规定,只有第一个低阶字节被写入,其余三个高阶字节被忽略。

public static void fileOutputStreamByteSingle(String file, String data) throws IOException {
    byte[] bytes = data.getBytes();
    try (OutputStream out = new FileOutputStream(file)) {
        out.write(bytes[6]);
    }
}

If we call this method with data as “Hello World!”, what we get as result is a file with the following text:

如果我们用 “Hello World!”的数据调用这个方法,我们得到的结果是一个有如下文字的文件。

W

This, as we can see, is the seventh character of the string indexed sixth.

我们可以看到,这是第六个索引的字符串的第七个字符。

4.2. write(byte[] b, int off, int length)

4.2.write(byte[] b, int off, int length)

This overloaded version of the write() method is there to write a sub-sequence of the byte array to the OutputStream.

这个重载版的write()方法是为了将字节数组的一个子序列写入OutputStream

It can write “length” number of bytes from the byte array as specified by the argument starting at an offset determined by “off” to the OutputStream:

它可以从参数指定的字节数组中,从 “off “确定的偏移量开始,向OutputStream:写入 “length “数目的字节。

public static void fileOutputStreamByteSubSequence(
  String file, String data) throws IOException {
    byte[] bytes = data.getBytes();
    try (OutputStream out = new FileOutputStream(file)) {
        out.write(bytes, 6, 5);
    }
}

If we now call this method with the same data as before, we get the following text in our output file:

如果我们现在用与之前相同的数据调用这个方法,我们在输出文件中得到以下文本。

World

This is the substring of our data starting at index five and comprising five characters.

这是我们的数据的子串,从索引五开始,包括五个字符。

4.3. write(byte[] b)

4.3.write(byte[] b)

This is yet another overloaded version of the write() method which can write an entire byte array as specified by the argument to the OutputStream.

这是write()方法的另一个重载版本,它可以写入由OutputStream参数指定的整个字节数组

This has the same effect as a call to write(b, 0, b.lengh):

这与调用write(b, 0, b.lengh)的效果相同。

public static void fileOutputStreamByteSequence(String file, String data) throws IOException {
    byte[] bytes = data.getBytes();
    try (OutputStream out = new FileOutputStream(file)) {
        out.write(bytes);
    }
}

When we call this method now with the same data, we have the entire String in our output file:

当我们现在用同样的数据调用这个方法时,我们的输出文件中有整个String

Hello World!

5. Direct Subclasses of OutputStream

5.OutputStream的直接子类

Now we’ll discuss some of the direct known subclasses of OutputStream which individually represent a specific data type of which the OutputStream they define.

现在我们将讨论一些直接已知的OutputStream的子类,它们分别代表了它们定义的OutputStream的特定数据类型。

They define their own methods apart from implementing those inherited from OutputStream.

除了实现那些从OutputStream继承的方法外,它们还定义了自己的方法。

We won’t go into the details of these subclasses.

我们不会去研究这些子类的细节。

5.1. FileOutputStream

5.1.FileOutputStream

As the name suggests, a FileOutputStream is an OutputStream to write data to a File. FileOutputStream, like any other OutputStream, can write a stream of raw bytes.

顾名思义,FileOutputStream一个OutputStream,用于向File写入数据。FileOutputStream,像其他OutputStream一样,可以写入原始字节流。

We have already examined different methods in FileOutputStream as part of the last section.

作为上一节的一部分,我们已经研究了FileOutputStream中的不同方法。

5.2. ByteArrayOutputStream

5.2.ByteArrayOutputStream

ByteArrayOutputStream is an implementation of OutputStream that can write data into a byte array. The buffer keeps growing as ByteArrayOutputStream writes data to it.

ByteArrayOutputStreamOutputStream的一个实现,可以将数据写入一个字节数组。当ByteArrayOutputStream向其写入数据时,缓冲区会不断地增长。

We can keep the default initial size of the buffer as 32 bytes or set a specific size using one of the constructors available.

我们可以保持缓冲区的默认初始大小为32字节,或者使用其中一个构造函数设置一个特定的大小。

The important thing to note here is that the method close() has practically no effect. The other methods in ByteArrayOutputStream can be safely called even after close() has been called.

这里需要注意的是,close()方法几乎没有影响。ByteArrayOutputStream中的其他方法即使在close()被调用后也可以安全地被调用。

5.3. FilterOutputStream

5.3.FilterOutputStream

OutputStream primarily writes a byte stream to a destination, but it can as well transform the data before doing so. FilterOutputStream represents superclass of all such classes which perform a specific data transformation. FilterOutputStream is always constructed with an existing OutputStream.

OutputStream主要是将一个字节流写到一个目的地,但它也可以在写之前对数据进行转换。FilterOutputStream代表所有执行特定数据转换的这类类的超类FilterOutputStream总是与现有的OutputStream一起构建。

Some of the examples of FilterOutputStream are BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream.

FilterOutputStream的一些例子是BufferedOutputStreamCheckedOutputStreamCipherOutputStreamDataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream

5.4. ObjectOutputStream

5.4.ObjectOutputStream

ObjectOutputStream can write primitive data types and graphs of Java objects to a destination. We can construct an ObjectOutputStream using an existing OutputStream to write to a specific destination like File.

ObjectOutputStream可以将原始数据类型和Java对象的图形写到一个目的地。我们可以使用现有的OutputStream构建一个ObjectOutputStream,以写入一个特定的目标,如File。

Please note that it is necessary for objects to implement Serializable for ObjectOutputStream to write them to a destination. You can find more details on Java Serialization here.

请注意,对象有必要实现Serializable,以便ObjectOutputStream将它们写到目的地。你可以在这里找到更多关于Java序列化的细节

5.5. PipedOutputStream

5.5.PipedOutputStream

A PipedOutputStream is useful to create a communication pipe. PipedOutputStream can write data which a connected PipedInputStream can read.

PipedOutputStream用于创建一个通信管道PipedOutputStream可以写入数据,而连接的PipedInputStream可以读取。

PipedOutputStream features a constructor to connect it with a PipedInputStream. Alternatively, we can do this later by using a method provided in PipedOutputStream called connect().

PipedOutputStream有一个构造函数来连接它和PipedInputStream。另外,我们可以通过使用PipedOutputStream中提供的connect()方法来完成这一工作。

6. OutputStream Buffering

6.OutputStream 缓冲

Input and output operations typically involve relatively expensive operations like disk access, network activity, etc. Performing this often can make a program less efficient.

输入和输出操作通常涉及相对昂贵的操作,如磁盘访问、网络活动等。经常进行这样的操作会使程序的效率降低。

We have “buffered streams” of data in Java to handle these scenarios. BufferedOutputStream writes data to a buffer instead which is flushed to the destination less often, when the buffer gets full, or the method flush() is called.

我们在Java中有 “缓冲数据流 “来处理这些情况。BufferedOutputStream 将数据写入一个缓冲区,而这个缓冲区在缓冲区满了或者调用flush()方法时,会较少地冲到目的地

BufferedOutputStream extends FilterOutputStream discussed earlier and wraps an existing OutputStream to write to a destination:

BufferedOutputStream扩展了前面讨论的FilterOutputStream,并包装了一个现有的OutputStream,以写入一个目标。

public static void bufferedOutputStream(
  String file, String ...data) throws IOException {
 
    try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
        for(String s : data) {
            out.write(s.getBytes());
            out.write(" ".getBytes());
        }
    }
}

The critical point to note is that every call to write() for each data argument only writes to the buffer and does not result in a potentially expensive call to the File.

需要注意的关键点是,每个数据参数对write()的每次调用都只写到缓冲区,而不会导致对File的潜在的昂贵调用。

In the case above, if we call this method with data as “Hello”, “World!”, this will only result in data being written to the File when the code exits from the try-with-resources block which calls the method close() on the BufferedOutputStream.

在上面的例子中,如果我们用 “Hello”、”World!”的数据来调用这个方法,只有当代码从try-with-resources块中退出时,才会导致数据被写入文件,该块在BufferedOutputStream上调用close()方法。

This results in an output file with the following text:

这导致输出文件中出现以下文字。

Hello World!

7. Writing Text with OutputStreamWriter

7.用OutputStreamWriter写文本

A byte stream, as discussed earlier, represents raw data which may be a bunch of text characters. Now we can get the character array and perform the conversion to the byte array ourselves:

如前所述,一个字节流代表原始数据,可能是一堆文本字符。现在我们可以得到字符数组,并自己执行转换为字节数组的工作。

byte[] bytes = data.getBytes();

Java provides convenient classes to bridge this gap. For the case of OutputStream, this class is OutputStreamWriter. OutputStreamWriter wraps an OutputStream and can directly write characters to the desired destination.

Java提供了方便的类来弥补这一差距。对于OutputStream的情况,这个类就是OutputStreamWriterOutputStreamWriter包装了一个OutputStream,可以直接将字符写到所需的目的地

We can also optionally provide the OutputStreamWriter with a character set for encoding:

我们还可以选择为OutputStreamWriter提供一个字符集的编码。

public static void outputStreamWriter(String file, String data) throws IOException {
    try (OutputStream out = new FileOutputStream(file); 
        Writer writer = new OutputStreamWriter(out,"UTF-8")) {
        writer.write(data);
    }
}

Now as we can see, we do not have to perform the transformation of the character array to the byte array before using FileOutputStream. OutputStreamWriter does this conveniently for us.

现在我们可以看到,在使用FileOutputStream之前,我们不必进行字符数组到字节数组的转换。OutputStreamWriter为我们方便地完成了这个任务。

Not surprisingly when we call the above method with data like “Hello World!”, this results into a file with text as:

毫不奇怪,当我们用 “Hello World!”这样的数据调用上述方法时,会产生一个文本为的文件。

Hello World!

8. Conclusion

8.结语

In this article, we discussed the Java abstract class OutputStream. We went through the interfaces it implements and the methods it provides.

在这篇文章中,我们讨论了Java的抽象类OutputStream。我们浏览了它实现的接口和它提供的方法。

Then we discussed some of the sub-classes of OutputStream available in Java. We finally talked about buffering and character streams.

然后我们讨论了Java中可用的OutputStream的一些子类。我们最后谈到了缓冲和字符流。

As always, the code for the examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over