http://tutorials.jenkov.com/java-nio/index.html
Java NIO: Channels and Buffers
In the standard IO API you work with byte streams and character streams. In NIO you work with channels and buffers. Data is always read from a channel into a buffer, or written from a buffer to a channel.
Java NIO: Non-blocking IO
Java NIO enables you to do non-blocking IO. For instance, a thread can ask a channel to read data into a buffer. While the channel reads data into the buffer, the thread can do something else. Once data is read into the buffer, the thread can then continue processing it. The same is true for writing data to channels.
Java NIO: Selectors
Java NIO contains the concept of "selectors". A selector is an object that can monitor multiple channels for events (like: connection opened, data arrived etc.). Thus, a single thread can monitor multiple channels for data.
Channels
Buffers
Selectors
Channels and Buffers
A Channel is a bit like a stream. From the Channel data can be read into a Buffer. Data can also be written from a Buffer into a Channel.
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
As you can see, these channels cover UDP + TCP network IO, and file IO.
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
These Buffer's cover the basic data types that you can send via IO. Java NIO also has a MappedByteBuffer which is used in conjunction with memory mapped files.
Selectors
A Selector allows a single thread to handle multiple Channel's. This is handy if your application has many connections (Channels) open, but only has low traffic on each connection
To use a Selector you register the Channel's with it. Then you call it's select() method. This method will block until there is an event ready for one of the registered channels. Once the method returns, the thread can then process these events. Examples of events are incoming connection, data received etc.
Channel
You can both read and write to a Channels. Streams are typically one-way (read or write).
Channels can be read and written asynchronously.
Channels always read to, or write from, a Buffer.
Basic Buffer Usage
Using a Buffer to read and write data typically follows this little 4-step process:
Write data into the Buffer
Call buffer.flip()
Read data out of the Buffer
Call buffer.clear() or buffer.compact()
When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call. In reading mode the buffer lets you read all the data written into the buffer.
Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data.
int bytesRead = inChannel.read(buf); //read into buffer.
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element.
Selector
The API calls to the NIO or IO classes.
The processing of data.
The number of thread used to process the data.
Path.normalize()
The normalize() method of the Path interface can normalize a path. Normalizing means that it removes all the . and .. codes in the middle of the path string, and resolves what path the path string refers to.
Files.createDirectory()
Files.copy()
Files.walkFileTree()
The FileVisitResult enum contains the following four options:
CONTINUE
TERMINATE
SKIP_SIBLINGS
SKIP_SUBTREE
Java NIO: Channels and Buffers
In the standard IO API you work with byte streams and character streams. In NIO you work with channels and buffers. Data is always read from a channel into a buffer, or written from a buffer to a channel.
Java NIO: Non-blocking IO
Java NIO enables you to do non-blocking IO. For instance, a thread can ask a channel to read data into a buffer. While the channel reads data into the buffer, the thread can do something else. Once data is read into the buffer, the thread can then continue processing it. The same is true for writing data to channels.
Java NIO: Selectors
Java NIO contains the concept of "selectors". A selector is an object that can monitor multiple channels for events (like: connection opened, data arrived etc.). Thus, a single thread can monitor multiple channels for data.
Channels
Buffers
Selectors
Channels and Buffers
A Channel is a bit like a stream. From the Channel data can be read into a Buffer. Data can also be written from a Buffer into a Channel.
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
As you can see, these channels cover UDP + TCP network IO, and file IO.
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
These Buffer's cover the basic data types that you can send via IO. Java NIO also has a MappedByteBuffer which is used in conjunction with memory mapped files.
Selectors
A Selector allows a single thread to handle multiple Channel's. This is handy if your application has many connections (Channels) open, but only has low traffic on each connection
To use a Selector you register the Channel's with it. Then you call it's select() method. This method will block until there is an event ready for one of the registered channels. Once the method returns, the thread can then process these events. Examples of events are incoming connection, data received etc.
Channel
You can both read and write to a Channels. Streams are typically one-way (read or write).
Channels can be read and written asynchronously.
Channels always read to, or write from, a Buffer.
Basic Buffer Usage
Using a Buffer to read and write data typically follows this little 4-step process:
Write data into the Buffer
Call buffer.flip()
Read data out of the Buffer
Call buffer.clear() or buffer.compact()
When you write data into a buffer, the buffer keeps track of how much data you have written. Once you need to read the data, you need to switch the buffer from writing mode into reading mode using the flip() method call. In reading mode the buffer lets you read all the data written into the buffer.
Once you have read all the data, you need to clear the buffer, to make it ready for writing again. You can do this in two ways: By calling clear() or by calling compact(). The clear() method clears the whole buffer. The compact() method only clears the data which you have already read. Any unread data is moved to the beginning of the buffer, and data will now be written into the buffer after the unread data.
RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); FileChannel inChannel = aFile.getChannel(); //create buffer with capacity of 48 bytes ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf); //read into buffer. while (bytesRead != -1) { buf.flip(); //make buffer ready for read while(buf.hasRemaining()){ System.out.print((char) buf.get()); // read 1 byte at a time } buf.clear(); //make buffer ready for writing bytesRead = inChannel.read(buf); } aFile.close();how a Channel can write data into a Buffer:
int bytesRead = inChannel.read(buf); //read into buffer.
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
compact() copies all unread data to the beginning of the Buffer. Then it sets position to right after the last unread element.
Selector
http://tutorials.jenkov.com/java-nio/selectors.html
A
four different events you can listen for:Connect
Accept
Read
Write
Creating a Selector
Selector selector = Selector.open();
Registering Channels with the Selector
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
This SelectionKey object contains a few interesting properties:
The interest set
The ready set
The Channel
The Selector
An attached object (optional)
Attaching Objects
selectionKey.attach(theObject);
Object attachedObj = selectionKey.attachment();
Selecting Channels via a Selector
Once you have register one or more channels with a Selector you can call one of the select() methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write).
selectedKeys()
Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set".
Main Differences Betwen Java NIO and IO
Stream Oriented vs. Buffer Oriented
Java IO being stream oriented means that you read one or more bytes at a time, from a stream. What you do with the read bytes is up to you. They are not cached anywhere. Furthermore, you cannot move forth and back in the data in a stream. If you need to move forth and back in the data read from a stream, you will need to cache it in a buffer first.
Java NIO's buffer oriented approach is slightly different. Data is read into a buffer from which it is later processed. You can move forth and back in the buffer as you need to. This gives you a bit more flexibility during processing. However, you also need to check if the buffer contains all the data you need in order to fully process it. And, you need to make sure that when reading more data into the buffer, you do not overwrite data in the buffer you have not yet processed.
Blocking vs. Non-blocking IO
http://tutorials.jenkov.com/java-nio/nio-vs-io.html
Java IO's various streams are blocking. That means, that when a thread invokes a read() or write(), that thread is blocked until there is some data to read, or the data is fully written. The thread can do nothing else in the meantime.
Java NIO's non-blocking mode enables a thread to request reading data from a channel, and only get what is currently available, or nothing at all, if no data is currently available. Rather than remain blocked until data becomes available for reading, the thread can go on with something else.
The same is true for non-blocking writing. A thread can request that some data be written to a channel, but not wait for it to be fully written. The thread can then go on and do something else in the mean time.
How NIO and IO Influences Application DesignA
Selector
is a Java NIO component which can examine one or more NIO Channel's, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections.
The
Notice the second parameter of the Channel
must be in non-blocking mode to be used with a Selector
. This means that you cannot useFileChannel
's with a Selector
since FileChannel
's cannot be switched into non-blocking mode. Socket channels will work fine though.register()
method. This is an "interest set", meaning what events you are interested in listening for in the Channel
, via the Selector
. There are four different events you can listen for:Connect
Accept
Read
Write
Creating a Selector
Selector selector = Selector.open();
Registering Channels with the Selector
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
This SelectionKey object contains a few interesting properties:
The interest set
The ready set
The Channel
The Selector
An attached object (optional)
Attaching Objects
selectionKey.attach(theObject);
Object attachedObj = selectionKey.attachment();
Selecting Channels via a Selector
Once you have register one or more channels with a Selector you can call one of the select() methods. These methods return the channels that are "ready" for the events you are interested in (connect, accept, read or write).
selectedKeys()
Once you have called one of the select() methods and its return value has indicated that one or more channels are ready, you can access the ready channels via the "selected key set".
Selector selector = Selector.open(); channel.configureBlocking(false); SelectionKey key = channel.register(selector, SelectionKey.OP_READ); while(true) { int readyChannels = selector.select(); if(readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while(keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if(key.isAcceptable()) { // a connection was accepted by a ServerSocketChannel. } else if (key.isConnectable()) { // a connection was established with a remote server. } else if (key.isReadable()) { // a channel is ready for reading } else if (key.isWritable()) { // a channel is ready for writing } keyIterator.remove(); } }A
FileChannel
cannot be set into non-blocking mode. It always runs in blocking mode.SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); while(true){ SocketChannel socketChannel = serverSocketChannel.accept(); if(socketChannel != null){ //do something with socketChannel... } }http://tutorials.jenkov.com/java-nio/nio-vs-io.html
Main Differences Betwen Java NIO and IO
Stream Oriented vs. Buffer Oriented
Java IO being stream oriented means that you read one or more bytes at a time, from a stream. What you do with the read bytes is up to you. They are not cached anywhere. Furthermore, you cannot move forth and back in the data in a stream. If you need to move forth and back in the data read from a stream, you will need to cache it in a buffer first.
Java NIO's buffer oriented approach is slightly different. Data is read into a buffer from which it is later processed. You can move forth and back in the buffer as you need to. This gives you a bit more flexibility during processing. However, you also need to check if the buffer contains all the data you need in order to fully process it. And, you need to make sure that when reading more data into the buffer, you do not overwrite data in the buffer you have not yet processed.
Blocking vs. Non-blocking IO
http://tutorials.jenkov.com/java-nio/nio-vs-io.html
Java IO's various streams are blocking. That means, that when a thread invokes a read() or write(), that thread is blocked until there is some data to read, or the data is fully written. The thread can do nothing else in the meantime.
Java NIO's non-blocking mode enables a thread to request reading data from a channel, and only get what is currently available, or nothing at all, if no data is currently available. Rather than remain blocked until data becomes available for reading, the thread can go on with something else.
The same is true for non-blocking writing. A thread can request that some data be written to a channel, but not wait for it to be fully written. The thread can then go on and do something else in the mean time.
The API calls to the NIO or IO classes.
The processing of data.
The number of thread used to process the data.
Path.normalize()
The normalize() method of the Path interface can normalize a path. Normalizing means that it removes all the . and .. codes in the middle of the path string, and resolves what path the path string refers to.
Files.createDirectory()
Files.copy()
Files.walkFileTree()
The FileVisitResult enum contains the following four options:
CONTINUE
TERMINATE
SKIP_SIBLINGS
SKIP_SUBTREE
Path rootPath = Paths.get("data/to-delete"); try { Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("delete file: " + file.toString()); Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.delete(dir); System.out.println("delete dir: " + dir.toString()); return FileVisitResult.CONTINUE; } }); } catch(IOException e){ e.printStackTrace(); }AsynchronousFileChannel
fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("result = " + result); attachment.flip(); byte[] data = new byte[attachment.limit()]; attachment.get(data); System.out.println(new String(data)); attachment.clear(); } @Override public void failed(Throwable exc, ByteBuffer attachment) { } });
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); ByteBuffer buffer = ByteBuffer.allocate(1024); long position = 0; buffer.put("test data".getBytes()); buffer.flip(); fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("bytes written: " + result); } @Override public void failed(Throwable exc, ByteBuffer attachment) { System.out.println("Write failed"); exc.printStackTrace(); } });http://ifeve.com/java-nio-all/