Java IO

Sharon Watkins
4 min readJun 18, 2021

Java IO is an API that comes with Java which is targeted at reading and writing data (input and output). Most applications need to process some input and produce some output based on that input. For instance, read data from a file or over network, and write to a file or write a response back over the network.

The Java IO API is located in the Java IO package (java.io). If you look at the Java IO classes in the java.io package the vast amount of choices can be rather confusing. What is the purpose of all these classes? Which one should you choose for a given task? How do you create your own classes to plugin? etc. The purpose of this tutorial is to try to give you an overview of how all these classes are grouped, and the purpose behind them, so you don’t have to wonder whether you chose the right class, or whether a class already exists for your purpose.

Java also contains another IO API called Java NIO. It contains classes that does much of the same as the Java IO and Java Networking APIs, but Java NIO can work in non-blocking mode. Non-blocking IO can in some situations give a big performance boost over blocking IO.

The input of one part of an application is often the output of another. Is an Output Stream a stream where output is written to, or output comes out from (for you to read)? After all, an Input Stream outputs its data to the reading program, doesn’t it? Personally, I found this a bit confusing back in the day when I first started out learning about Java IO.

Java’s IO package mostly concerns itself with the reading of raw data from a source and writing of raw data to a destination. The most typical sources and destinations of data are these:

  • Files
  • Pipes
  • Network Connections
  • In-memory Buffers (e.g. arrays)
  • System.in, System.out, System.error

IO Streams: are a core concept in Java IO. A stream is a conceptually endless flow of data. You can either read from a stream or write to a stream. A stream is connected to a data source or a data destination. Streams in Java IO can be either byte based (reading and writing bytes) or character based (reading and writing characters).

A program that needs to read data from some source needs an Input Stream or a Reader. A program that needs to write data to some destination needs an Output Stream or a Writer.

An Input Stream or Reader is linked to a source of data. An Output Stream or Writer is linked to a destination of data.

Java IO contains many subclasses of the InputStream, OutputStream, Reader and Writer classes. The reason is, that all of these subclasses are addressing various different purposes. That is why there are so many different classes. The purposes addressed are summarized below:

  • File Access
  • Network Access
  • Internal Memory Buffer Access
  • Inter-Thread Communication (Pipes)
  • Buffering
  • Filtering
  • Parsing
  • Reading and Writing Text (Readers / Writers)
  • Reading and Writing Primitive Data (long, int etc.)
  • Reading and Writing Objects

Closing a stream when it’s no longer needed is very important. That is why CopyCharacters uses a finally block to guarantee that both streams will be closed even if an error occurs. This practice helps avoid serious resource leaks.

One possible error is that CopyCharacters was unable to open one or both files. When that happens, the stream variable corresponding to the file never changes from its initial null value. That’s why CopyCharacters makes sure that each stream variable contains an object reference before invoking close.

Character I/O is usually processed in units longer than single characters. One common unit is the line: a string of characters with a line terminator at the end. A line terminator can be a carriage-return/line-feed sequence (“\r\n”), a single carriage-return (“\r”), or a single line-feed (“\n”). Supporting all possible line terminators allows programs to read text files created on any of the widely used operating systems.

Java BufferedReader class is used to read the text from a character-based input stream. It can be used to read data line by line by readLine() method. It makes the performance fast. It inherits Reader class.

The Java PrintWriter class (java.io.PrintWriter) enables you to write formatted data to an underlying Writer. For instance, writing int, long and other primitive data formatted as text, rather than as their byte values.

Invoking readLine returns a line of text. This line is then output using PrintWriter’s println method, which appends the line terminator for the current operating system. This might not be the same line terminator that was used in the input file.

Scanner is a class in java.util package used for obtaining the input of the primitive types like int, double etc. and strings. It is the easiest way to read input in a Java program, though not very efficient if you want an input method for scenarios where time is a constraint like in competitive programming.

To create an object of Scanner class, we usually pass the predefined object System.in, which represents the standard input stream. We may pass an object of class File if we want to read input from a file.

To read numerical values of a certain data type XYZ, the function to use is nextXYZ(). For example, to read a value of type short, we can use nextShort()

To read strings, we use nextLine().

To read a single character, we use next().charAt(0). next() function returns the next token/word in the input as a string and charAt(0) funtion returns the first character in that string.

Scanner also supports tokens for all of the Java language’s primitive types (except for char), as well as BigInteger and BigDecimal. Also, numeric values can use thousands separators. Thus, Scanner correctly reads the string “32,767” as representing an integer value.

--

--