If you’ve ever opened java.io, I’m sure you’ve been surprised by how many APIS there are for I/O, but don’t be afraid. Today I’m going to take you through Java I/O from a design pattern perspective.

What is the I/O

Input /output, usually the input and output of data between internal storage and external storage or other peripheral devices. Today, THE I/O problem is at the heart of the whole human-computer interaction, because I/O is the main channel through which machines obtain and exchange information.

However, I/O can be divided into data format and transmission mode, which are the key factors affecting efficiency. :pear:

Data formats are as follows:

  • Bytes: InputStream and OutputStream
  • Characters: Writer and Reader

Transmission mode is divided into:

  • Disk operation: File
  • Network operation: Socket

The conversion between bytes and characters

All computer I/O operations are based on bytes, but why there are character operations? This is because the data we operate in the program is usually in the form of characters. Therefore, Writer and Reader are provided to directly read and write characters for ease of operation.

I’ll look at bytes and characters from the perspective of adapter patterns. :lollipop:

Analysis from the source point of view

// Implement the Reader interface
public class InputStreamReader extends Reader {
	// Object for codec
	private final StreamDecoder sd;
	public InputStreamReader(InputStream in) {
		super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            // The default encoding should always be available
            throw newError(e); }}public int read(a) throws IOException {
        returnsd.read(); }}Copy the code

Each InputStreamReader inherits Reader and then indirectly owns an InputStream instance via StreamDecoder because byte to char is codeced. So InputStreamReader is an adapter between bytes and characters, and OutputStreamReader is a similar implementation.

FilterInputStream

Next I’ll look at the architecture of the entire java.io package from the perspective of FilterInputStream.

In decorator mode, InputStream is the base class that needs to be decorated, and FilterInputStream is the base class for all decorators. :cake:

java.io

We can now roughly divide the java.io package into the following situations. :watermelon:

  • Some basic interfaces.

    Examples are Closeable, Readable, DataInput.

  • All subclasses of Reader/Writer, which are character-reading adapters, and extensions to adapters.

    For example: InputStreamReader, FileReader, BufferedReader, CharArrayReader.

  • All subclasses of InputStream/OutputStream, which are various instances of byte reading and writing, are decorated objects.

    For example, FileInputStream, SocketInputStream, StringBufferInputStream, and ByteArrayInputStream.

  • All subclasses of FilterInputStream/FilterOutputStream these are decorators, packaging can be repeated.

    For example, PushbackInputStream, BufferedInputStream, DataInputStream, and LineNumberInputStream.

Of course, this doesn’t completely describe all classes under the java.io package, but it does give us a general, macro view of them that allows us to analyze specific objects in depth based on our needs.