Skip to main content

I/O in Java - NIO vs IO (Part 2)

Java NIO is an alternate IO API since Java 1.4. It offers a different way to work with I/O than the standard IO APIs. Java NIO allows high speed I/O without having to write custom native code. NIO moves the most time-consuming I/O activities (namely, filling and draining buffers) back into the operating system, thus allowing for a great increase in speed.

In this post, we will be discussing the basic differences between IO and NIO in detail.

Blocking vs. Non-blocking I/O

Blocking I/O wait for the data to be read or written before returning and IO streams are blocking in nature. In other words, when a thread invokes read() or write(), then thread is blocked until some data is available for reading, or the data is fully written.

Non-blocking I/O does not wait for the data to be read or written before returning. Java NIO is non-blocking in nature. This mode allows the thread to request writing data to a channel, but not wait for it to be fully written. The thread is allowed to do something else in the meantime.

Stram vs. Buffer oriented

Java IO is stream-oriented i.e. data is read one or more bytes at a time from a stream. It uses streams for transferring the data between a data source/sink and a java program. The I/O operation using this approach is slow.
Stream oriented
Furthermore, the data is not cached anywhere and we cannot move back and forth in the data in the stream. If we want to move back and forth, then we need to cache data in the buffer first.

Java NIO's buffer oriented approach is a little different. Data is read into a buffer from which it is processed later. We can also move back and forth in the buffer as per need. However, we also need to check if the buffer has all the data we need in order to process it. Also, we need to be careful while reading more data into the buffer, we do not overwrite the data which we have not yet processed.

Buffer oriented
Java NIO deals with Channels and Buffers. A channel is like a stream which represents a connection between data source/sink and code.

A buffer is an object which stores some data. The addition of the buffer object in NIO marks one of the most significant differences between the new library and original I/O. In stream-oriented I/O, we wrote data directly to, and read data directly from, Stream objects.

In the NIO library, all data is handled with buffers. When data is read, it is read directly into a buffer. When data is written, it is written into a buffer. Anytime you access data in NIO, we are pulling it out of the buffer.

Channels

It is a medium that transports data efficiently between the entity and byte buffers. It reads data from the entity and places it inside a buffer block for use.

Channels act as gateway provided by java NIO to access the I/O mechanism. Usually, channels have a one-to-one relationship with operating system file descriptor for providing the platform independence operational feature.

Selectors

Java NIO’s selectors allow a single thread to monitor multiple channels of input. We can register multiple channels with a selector, then use a single thread to “select” the channels that have input available for processing or select the channels that are ready for writing. This selector mechanism makes it easy for a single thread to manage multiple channels.

Implementation of IO and NIO

Here let's see an example of reading a file using both IO and NIO APIs
  • IO API
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private static void readFileUsingIO() {

        // This string variable will hold one line of the file one by one
        String line;

        // Buffered instance to get buffer
        BufferedReader bufferedReader = null;

        try {
            // Creating an instance of FileReader to read the file by providing the path
            FileReader fileReader = new FileReader(filePath);

            // Creating the instance of BufferedReader to read text file
            bufferedReader = new BufferedReader(fileReader);

            while ((line = bufferedReader.readLine()) != null) {

                // Printing the line
                System.out.println(line);
            }

        } catch (IOException e) {

            e.printStackTrace();

        } finally {
            // Close the BufferedReader to avoid memory leaks
            try {

                if (bufferedReader != null) {
                    bufferedReader.close();
                }

            } catch (IOException e) {

                e.printStackTrace();
            }
        }
    }
  • NIO API

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private static void readFileUsingNIO() {

        try {

            // Create an instance of RandomAccessFile to read to file
            RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "r");

            // Getting the instance of channel
            FileChannel fileChannel = randomAccessFile.getChannel();

            // ByteBuffer with capacity of 1024 bytes
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

            // Read from the ByteBuffer
            while (fileChannel.read(byteBuffer) > 0) {

                byteBuffer.flip();

                for (int i = 0; i < byteBuffer.limit(); i++) {

                    // Read character by character
                    System.out.print((char) byteBuffer.get());
                }
                byteBuffer.clear();
            }

            // Closing channel and file instance to avoid memory leaks
            fileChannel.close();
            randomAccessFile.close();

        } catch (IOException e) {

            e.printStackTrace();

        }
    }

Conclusion

Today we discussed difference between normal IO and NIO APIs with an example which reads a file.  

You can find the complete on my GitHub repository.

I would love to hear your thoughts on this and would like have suggestions from you to make it better. 

Feel free to befriend me on FacebookTwitter or Linked In or say Hi by email.

Happy Coding 😊

Comments

Popular posts from this blog

Threads in Java - Masterclass (Part 0)

Multithreading is a way to introduce concurrency in a program. In any case, if there are parallel paths in our program (parts which do not depend on the result from another part), we can make use of multithreading.
One should exploit this feature, especially with all these multiple core machines nowadays.

Below are a few reasons why we should use multithreading -
1. Keep a process responsive There was once a time when you would print a document in MS Word and the application would freeze for an annoyingly long amount of time until the job finished. Eventually, Microsoft solved this problem by running a printing job parallel to the main thread/ GUI thread.  To be clear though, not only GUI apps but Network services have to keep an ear to the ground for new clients, dropped connections and cancellation requests. In either case, it is critical to do the heavy lifting on a secondary thread to keep the user satisfied. 2. Keep a processor busy Keeping a processor busy can be a tough task e…

Parsing XML using Retrofit

Developing our own type-safe HTTP library to interface with a REST API can be a real pain as we have to handle many aspects -
making connectionscachingretrying failed requeststhreadingresponse parsingerror handling, and more.  Retrofit, on the other hand, is a well-planned, documented and tested library that will save you a lot of precious time and headaches. In this tutorial, we are going to discuss how we can parse the XML response returned from https://timesofindia.indiatimes.com/rssfeedstopstories.cms using the Retrofit library.

To work with Retrofit, we need three classes -  Model class to map the JSON dataInterfaces which defines the possible HTTP operationsRetrofit.Builder class - Instance which uses the interface and the Builder API which allows defining the URL endpoint for the HTTP operation. Every method of the above interface represents on possible API call. The request type is specified by using appropriate annotations (GET, POST). The response is returned as a Call object…

Material design profile page in Android

Hey everyone, some days back I was working on one my personal Android project. In that project, I was supposed to create a simple profile page for a user. This profile page was supposed to show some basic details of a user.

The output of this UI will be like this -
I created the profile page using material design and in this post, I am going to discuss a step by step tutorial to create a simple yet elegant profile page. Without further ado, let's get started.
Creating a new project Click on File ➤ New Project ➤ Empty Activity and fill the necessary details. Change styles.xml fileNavigate to app\src\main\res\values\styles.xmlChange the style value from DarkActionBar to NoActionBar as below<resources><!-- Base application theme. --><stylename="AppTheme"parent="Theme.AppCompat.Light.NoActionBar"><!-- Customize your theme here. --><itemname="colorPrimary">@color/colorPrimary</item><itemname="colorPrimaryDark&qu…