Reference document: Getting started with new I/O (NIO)

Preface:

NIO was introduced with JDK1.4 for high speed, block oriented I/O in standard Java code. By defining classes to hold data, and by processing that data in blocks, NIO takes advantage of low-level optimizaitons compared to I/O package could not, without using native libraries.

We will cover most aspect of the NIO library, from high level conceptual stuff to under-the-hood programming detail. To learning about crucial I/O elements like buffers and channels, we will also see how standard I/O elements works in the updated library. You'll also learn about things you can only do with NIO, such as asynchronous I/O and direct buffers.

Input/output: A conceptual overview

I/O in Java programming, I/O has until recently been carried out using a stream metaphor. All I/O is viewed as the movement of single bytes, one at a time, through an object called a stream. Stream I/O is used for contacting the outside world, and it can also used internally for turning objects into bytes and then back into objects.

NIO plays the same role as original I/O, but it uses a different metaphor -- block I/O. As you can see the Java NIO Buffers, the block I/O is more efficient than stream I/O.

Why NIO?

NIO was created allow Java program to implement 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 OS, thus allowing great increase in speed.

Streams vs blocks

The most important distinction between the original I/O library and NIO has to do with how data is packaged and transmitted. The original I/O deals with data in streams, whereas NIO do with data in blocks.

A stream-oriented I/O system deals with data one byte at a time. An input stream produces one byte of data, and an output stream consumes one byte of data. It's very easy to create filters for stream data , also relatively simply to chain several filters together so that each one does its part in what amounts to single sophisticated processing mechanism. On the flip side, stream-oriented I/O is often rather slow.

Integrated I/O

The original I/O package and NIO have been well integrated in JDK 1.4 java.io.* has been reimplemented using NIO as its base , so it can now take advantage of some features of NIO. For example some java some of classes in the java.io.* package contain methods to read and write data in blocks, which leads to faster processing.

Channel and buffers

Channels and buffers are the central
objects in NIO, and are used for just about every I/O operation.
Channels are analogous to stream in the original IO package. All data
that goes anywhere must pass through a Channel object. A buffer is
essentially a container object. All data that is sent to a channel
must first be placed in a buffer. So any data that is read from a
channel is read into buffer.

What
is a buffer?

A buffer is an object, which is essentially an array. It's an
array of bytes, but other kinds of arrays can be used. But a buffer
is more than just an array. A buffer provides structured access to
data and also keeps track of the system's read/write processes.

In the NIO library, all data is handled with buffers. When data is
read, it's read directly into a buffer, when data is written, it's
written into a buffer. Anytime you access data in NIO, you are
pulling it out of the buffer. A buffer is essentially an array.

What 's a channel ?
A channel is an object from which you can
read data and to which you can write data.Comparing NIO with original
I/O, a channel is like a stream.

Kinds of Channel

Channels differ from stream in that they are bi-directional.
Whereas streams only go in one direction (a stream must be a subclass
of either InputStream or OutputStream), a channel can be opened for
reading, for writing, or for both.

Because they are bi-directional, channels better reflect the
reality of the underlying OS than streams do. In the UNIX model in
particular, the underlying OS channels are bi-directional.

Practice: Reading and
writing in NIO

Reading from a channel is simple: we create a buffer and then ask
a channel to read data into it. Writing data we just create a buffer,
fill it will data, and then ask a channel to write from it.

Reading from a file

For our first exercise, we'll read some data from a file. If we
are using original IO, we will simply create a FileInputStream and
read from that.

In NIO, however, things work a little differently; we first get Channel object from the FileInputStream, and then use that channel to read the data.

Any time you perform a read operation in an NIO system.you are reading from a channel, but you don’t read directly from  a channel. Since the data ultimate resides in the buffer, you read from a channel to a buffer.

So reading from a file involves three steps:

  1. getting the Channel from FileInputStream;
  2. creating the Buffer
  3. reading from the Channel into the buffer

Three easy steps:
Our first step is to get a channel. We get the channel from the FileInputStream.

FileInputStream fin = new FileInputStream("DirectMem.java");
FileChannel fc = fin.getChannel();

The next step is to create a buffer and read from the channel into the buffer, as shown here:

ByteBuffer buffer = ByteBuffer.allocate(1024);
fc.read(buffer);

We don't need to tell the channel how much to read into buffer. Each buffer has ssophisticated internal accounting system that keeps track of how much data has been read and how much room there is for more data. We will discuss the Buffer internals overview then.

Writing to a file

Writing is similiar to reading from a file. Here is the sample code:

    private static void readingWritingFromFile() throws IOException{
String fileName = "DirectMem.java";
FileInputStream fin = new FileInputStream(fileName);
FileChannel fc = fin.getChannel(); int bufLen = 2<<10;
ByteBuffer buffer = ByteBuffer.allocate(bufLen);
fc.read(buffer); String newFileName = "newDirectMem.txt";
FileOutputStream fout = new FileOutputStream(newFileName);
FileChannel writeFc = fout.getChannel(); ByteBuffer newBuf = ByteBuffer.allocate(bufLen);
String message = "test writing to channel from buffer";
byte[] mesArray = message.getBytes();
for (int i = 0; i < mesArray.length; i++) {
newBuf.put(mesArray[i]);
}
newBuf.flip();
writeFc.write(newBuf); }

Other reading and writing operation please see Reading and Writing with Java NIO

There some examples we combine reads data into the buffer from the input channel, fcin, and the second line writes the data to the output channel, fcout. Notice that before reading into a buffer from the input channel we call the method clear(), and before write newly read data into another channel we call the flip() method prepare the buffer.

Buffer internals

In this section, we will see 2 components of buffers in NIO: state variables and accessor methods.

State variables are key to the "internal accouting system" mentioned in the previous section. With each read/write operation, the internal states changes. By recording and tracking those changes, a buffer is can manage it's own resources.

A buffer has many states, in some cases write data directly into another channel, but often you'll want to look at the data itself. This is acopmlished using the accessor method get(), while if if you want to put raw data in a buffer, you use the accessor method put().

State variables

3 values can be used to specify the state of a buffer:

  • position
  • limit
  • capacity

these variables track the state of the buffer and the data is contains. We'll examine each one in detail, and also see how to fit read/write process. For the sake of the example, we'll assume that we are copying data from an input channel to an output channel.

Position

You will recall that a buffer is really just a glorified array when you read from a channel, position records how much data you have written. It specifies into where is array element the next byte. If you write to a channel, postion will record how much data read from the buffer. It refers to the next eelement you want to read.

Limit

The limit variable specifies how much data there is left to get, or how much room left to put data into.

Capacity

The capacity of a buffer sepcifies the maximum amount of data that can be stored therein. It specifies the size of underlyging array.

The limit is smaller than capacity.

We create buffer as example, let's assume that our buffer capacity is 8 bytes, and the buffer states is shown:

React operations

The limit can not be larger than the ccapacity, and in this case both values are set to 8. We show this by pointing them off the end of the array. The position is set to 0, when read data into the buffer, then the next byte read will be put into slot0; If we write from the buffer, the next byte taken from the buffer will be taken from slot 0.

React operations

When we read data into the buffer, increase the position. In this example we read 5 bytes so add 5 to pposition.

After read byte into buffer from channel, we want write bytes from buffer to channel. But before change ooperation to buffer, we should first call the flip() function. It resets position to 0, and set limit to the position old value.

React operations

You can see the posiiton set to 0 and limit set to 5(Meaning all data we read from buffer just now), Then we begin write bytes from the buffer to channel. And we read 5 bytes from the buffer, add 5 to position and now you can see position is equal to limit.

When all read and write operations finished, we call clear() method to clear all variables:

1. reset positon to 0.

2. limit set to capacity

Conclusion

If you want manipulate data in disk you should firstly read it into buffer from the channel, or if you want to store data back to disk you should write channel from the buffer.

For more detail about manipulation about buffer, please see Java NIO read/write file through FileChannel

brief introduction JAVA new I/O (NIO)的更多相关文章

  1. Java I/O and NIO [reproduced]

    Java I/O and NIO.2---Five ways to maximize Java NIO and NIO.2---Build more responsive Java applicati ...

  2. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  3. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  4. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  5. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  6. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  7. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  8. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  9. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

随机推荐

  1. c# 根据中文汉字获取到拼音

    public static String ConvertToPinyin(String str) { if (String.IsNullOrEmpty(str)) return String.Empt ...

  2. iOS状态栏字体设置为白色

    info.plist 添加字段: view controller -base status bar appearence 设为NO [[UIApplication sharedApplication] ...

  3. Linux学习之修改主机名

    1.临时修改主机名 显示主机名: oracle@localhost:~$ hostname localhost 修改主机名: oracle@localhost:~$ sudo hostname orc ...

  4. 管理node_modules

    http://stackoverflow.com/questions/15225865/centralise-node-modules-in-project-with-subproject

  5. 提示constructor无法location的原因

    1.缺少对应属性的set方法 2.缺少确实没有对应的方法 3.对应的构造方法中参数类型不匹配 4.java对象不会在寻找构造函数时执行数据类型的强制类型转换,没有对应的类型就返回异常,不会自动强制转换 ...

  6. byte与sbyte的转换

    C#实现byte与sbyte的转换 byte[] mByte; sbyte[] mSByte = new sbyte[mByte.Length]; ; i < mByte.Length; i++ ...

  7. SendMessage基本认识

    SendMessage基本认识 函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数PostMessage不同,将一个消息寄送到一个线 ...

  8. Debug程序无法运行解决

    说明:文章内容部分参考网络上的解决思路. 在没有安装Microsoft Visual Studio的系统上,Debug版本无法正常运行.这是由于缺少vs运行时库引起的. 以vs2005为例.开发机用v ...

  9. NOI2014 Day1

    NOI2014 Day1 起床困难综合症 题目描述:给出\(n\)个操作,每个操作包含一种运算\((XOR.OR.AND)\)和一个数,已知一开始的数字为\([0, m]\),问经过\(n\)次操作后 ...

  10. bootstrap-dialog的使用

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...