Java.nio vs Java.io
By Nino Guarnacci on Jun 18, 2009
……… posted by Davide Pisano
This document is not a Java.io or a Java.nio manual, or a technical document about Java.io and Java.nio use. It only attempts to compare these two packages, highlighting differences and features in the most simple way. Java.nio presents new stream communication aspects and inserts new buffer, file streaming and socket features.
This package is used for system input and output through data streams, and serialization. Streams support many different kinds of data, including simple bytes, primitive data types, localized characters, and objects. A stream is a sequence of data: a program uses an input stream to read data from a source.
About InputStream and OutputStream
Performing InputStream operations or OutputStream operations means generally having a loop that reads the input stream and writes the output stream one byte at a time. You can use buffered I/O streams for an overhead reduction (overhead generated by each such request often triggers disk access, network activity, or some other operation that is relatively expensive). Buffered input streams read data from a memory area known as a buffer; the native input API is called only when the buffer is empty. Similarly, buffered output streams write data to a buffer, and the native output API is called only when the buffer is full. Those buffered API wrap the unbuffered streams: BufferedInputStream and BufferedOutputStream.
The above section focuses on streams, which provide a simple model for reading and writing data. Streams work with a large variety of data sources and destinations, including disk files. However, streams don't support all the operations that are common with disk files.The following links give information on non-stream file I/O. There are two topics:
File is a class that helps to write platform independent code for examining and manipulating files and directories.
Random access files support non sequential access to disk file data.
A socket is one endpoint of a two-way communication link between two programs running on the network. Socket classes are used to represent the connection between a client program and a server program. The java.net package provides two classes: Socket and ServerSocket. These implement the client side of the connection and the server side of the connection, respectively.
The client knows the host-name of the machine on which the server is running ,and the port number on which the server is listening. Clients try to connect to the server and if everything goes well, the server accepts the connection. Upon acceptance, the server gets a new socket bound to the same local port and also has its remote endpoint set to the address and port of the client. It needs a new socket so that it can continue to listen to the original socket for connection requests while tending to the needs of the connected client.
The server waits for a client connection in blocking mode: serverSocket.accept() is a blocking instruction, the server waits for a connection and no other operation can be executed by the thread which runs the server. Because of this, the server can work in multitasking only by implementing a multi-thread server: having to create a thread for every new socket created by the server.
The I/O performance, often, is a modern application critical aspect. Operative Systems (OS) continuously improve the I/O performance. JVM provides a uniform operating environment that helps the Java programmer in most of the differences between operating-system environments. This makes it faster and easier to write, but the OS feature becomes hidden. To increase IO performance you could write a specific code to access the OS feature directly, but this isn’t the best solution - your code could be OS dependent. Java.nio provides new equipment to address this problem. It provides high-performance I/O features to perform operations on commonly available commercial operating systems today.
The NIO packages of JDK 1.4 introduce a new set of abstractions for doing I/O.
Java.nio is the new package that implements the New I/O APIs for the Java Platform. The NIO APIs include the following features:
Buffers for data of primitive types
Character-set encoders and decoders
A pattern-matching facility based on Perl-style regular expressions
Channels, a new primitive I/O abstraction
A file interface that supports locks and memory mapping
A multiplexed, non-blocking I/O facility for writing scalable servers
At the sun site is it possible to find exhaustive technical documentation about java.nio. Now I’ll explain some of nio's aspects to show the difference betwen the old library java.io. and java.nio. Be advised, java.nio is not a java.io substitute, rather it is a java.io ‘expansion’. Nio's birth has caused a revision of Io's class and interface (look at this link).
One of the most important aspects of NIO is the ability to operate in non-blocking mode, denied to the traditional java I/O library. But what is non-blocking mode?
Non blocking mode
The bytes of an I/O stream must be accessed sequentially. Devices, printer ports, and network connections are common examples of streams.
Streams are generally, but not necessarily, slower than block devices, and are often the source of intermittent input. Most operating systems allow streams to be placed into non-blocking mode, which permits a process to check if input is available on the stream, without getting stuck if none is available at a given moment. Such a capability allows a process to handle input as it arrives but perform other functions while the input stream is idle. The operating system can be told to watch a collection of streams and indicate which of those streams are ready. This ability permits a process to multiplex many active streams using common code and a single thread by leveraging the readiness information returned by the operating system. This is widely used in network servers to handle large numbers of network connections.
Starting from the simplest and building up to the most complex, the first improvement to mention is the set of Buffer classes found in the java.nio package. These buffers provide a mechanism to store a set of primitive data elements in an in-memory container. A Buffer object is a container for a fixed amount of data, a container where data can be read and written.
All buffers are readable, but not all are writable. Each buffer class implements isReadOnly() to indicate whether it will allow the buffer content to be modified.
Buffers work with channels. Channels are portals through which I/O transfers take place, and buffers are the sources or targets of those data transfers. Data you want to send is placed in a buffer, which is passed to a channel; otherwise, a channel deposits data in a buffer you provide.
A Channel is like a tube that transports data efficiently between byte buffers and the entity on the other end of the channel. Channels are gateways through which the native I/O services of the operating system can be accessed with a minimum of overhead, and buffers are the internal endpoints used by channels to send and receive data.
Channels can operate in blocking or non-blocking modes. A channel in non-blocking mode never puts the invoking thread to sleep. The requested operation either completes immediately or returns a result indicating that nothing was done. Only stream-orientated channels, such as sockets can be placed in nonblocking mode. In the java.nio channel family there are FileChannel, ServerSocketChannel and SocketChannel; these are specific channels created for file and socket management.
FileChannels are read/write channels, they are always blocking and cannot be placed into nonblocking mode. The nonblocking paradigm of stream-oriented I/O doesn't make as much sense for file-oriented operations because of the fundamentally different nature of file I/O.
FileChannel objects cannot be created directly. A FileChannel instance can be obtained only by calling getChannel() on an open file object (RandomAccessFile, FileInputStream, or FileOutputStream). GetChannel() method returns a FileChannel object connected to the same file, with the same access permissions as the file object. FileChannel objects are thread-safe. Multiple threads can concurrently call methods on the same instance without causing any problems, but not all operations are multi-thread. Operations that affect the channel's position or the file size are single-threaded.
Using FileChannel, operations like file copy become a channel to channel trasfer (transferTo() and transferFrom())and read/write operations become easy using buffers.
SocketChannel is different to FileChannel: The new socket channels can operate in nonblocking mode and are selectable. It's no longer necessary to dedicate a thread to each socket connection, Using the new NIO classes, one or a few threads can manage hundreds or even thousands of active socket connections with little or no performance loss. It's possible to perform readiness selection of socket channels using a Selector object.
There are three socket channel type: SocketChannel, ServerSocketChannel, and DatagramChannel; SocketChannel and DatagramChannel are able to read and write, ServerSocketChannel listens for incoming connects and creates new SocketChannel objects. All the socket channels create a peer socket object when they are instantiated (java.net sockets). The peer socket can be obtained from a channel by invoking its socket() method. While every socket channel (in java.nio.channels) has an associated java.net socket object, not all sockets have an associated channel. If you create a Socket object in the traditional way, by instantiating it directly, it will not have an associated SocketChannel, and its getChannel() method will always return null.
Socket channels can operate in nonblocking mode. The blocking nature of traditional Java sockets has traditionally been one of the most significant limitations to Java application scalability. Non-blocking I/O is the basis upon which many sophisticated, high-performance applications are built. Setting or resetting a channel's blocking mode is easy. Simply call configureBlocking().
Nonblocking sockets are usually thought of for server-side use because they make it easier to manage many sockets simultaneously.
Selectors provide the ability to have a channel readiness selection, which enables multiplexed I/O. To understand selector feature, I can explain selector advantage using the following example.
Imagine you are in a train station (non-selector), and there are three platforms (channels), and on each platform a train arrives (buffer). On each platform there is a controller for each arrived train (worker thread). That is non-selector. Now imagine selector. There are three platforms (channel), on each platform arrives a train (buffer), and each platform has an indicator (a bell for example) that says “Train arrived” (selection key). In this instance there is only one controller for all three platforms. He looks at the indicator (selector.select()) to find out if a train has arrived and goes to meet that train.
It's simple to understand the advantages of using selector: with a single thread you can obtain a multitasking application. As well as this, you can obtain more advantages using non-blocking selector! Imagine that the train controller looks at the indicator: he can wait for a new train and not do any other thing (blocking mode using selector.select()). But he can instead control tickets, for example, while waiting for a new train (non-blocking mode using selector.selectNow()). In this way selector returns null and continue to execute code.
IO vs. NIO
NIO construction makes I/O faster than traditional I/O. In a program where the I/O operations constitute a significant amount of the processing, expect to see some difference. For example if an application has to copy files or transfer bytes using sockets, using Nio is possible to obtain a faster performance because it is closer to the OS than the I/O API. Increasing the byte size, the difference becomes more appreciable. Nio also provides other features not in io API, for streaming operations. However, it is not possible to substitute IO with NIO because NIO API adds functionalities to the java.io. NIO extends the native IO API introducing new possibilities for the developer to manipulate stream data in a powerful way.
“JAVA NIO” - Ron Hitchens - Publisher: O'Reilly
……… posted by Davide Pisano