绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
Getting started with new I/O (NIO)--reference
2020-01-06 09:56:44

The new input/output (NIO) library, introduced with JDK 1.4, provides high-speed, block-oriented I/O in standard Java code. This hands-on tutorial covers the NIO library in great detail, from the high-level concepts to under-the-hood programming detail. You'll learn about crucial I/O elements like buffers and channels, and examine how standard I/O works in the updated library. You'll also learn about things you can do only with NIO, such as asynchronous I/O and direct buffers.

Before you start

About this tutorial

The new input/output (NIO) library was introduced with JDK 1.4. Picking up where original I/O leaves off, NIO provides 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 optimizations in a way that the original I/O package could not, without using native code.

In this tutorial, we'll cover almost every aspect of the NIO library, from the high-level conceptual stuff to under-the-hood programming detail. In addition to learning about crucial I/O elements like buffers and channels, you'll have the opportunity to see how standard I/O works in the updated library. You'll also learn about things you canonlydo with NIO, such as asynchronous I/O and direct buffers.

Throughout the tutorial, we'll work with code samples that illustrate different aspects of the NIO library. Almost every code sample is part of an extended Java program, which you'll find inResources. As you are working through the exercises, you're encouraged to download, compile, and run these programs on your own system. The code will also come in handy when you're done with the tutorial, providing a starting point for your NIO programming efforts.

This tutorial is intended for any programmer who wants to learn more about the JDK 1.4 NIO library. To get the most from the discussion you should understand basic Java programming concepts such as classes, inheritance, and using packages. Some familiarity with the original I/O library (from thejava.io.*package) will also be helpful.

While this tutorial does require a working vocabulary and conceptual understanding of the Java language, it does not require a lot of actual programming experience. In addition to explaining thoroughly all the concepts relevant to the tutorial, I've kept the code examples fairly small and simple. The goal is to provide an easy entry point for learning about NIO, even for those who don't have much Java programming experience.

How to run the code

The source code archive (available inResources) contains all of the programs used in this tutorial. Each program consists of a single Java file. Each file is identified by name and easily related to the programming concept it illustrates.

Some of the programs in the tutorial require command-line arguments to run. To run a program from the command line, simply go to your nearest command-line prompt. Under Windows, the command-line prompt is the "Command" or "command.com" program. Under UNIX, any shell will do.

You will need to have JDK 1.4 installed and in your path to complete the exercises in the tutorial. SeeResourcesif you need help installing and configuring JDK 1.4.

 

Input/output: A conceptual overview

Intro to I/O

I/O -- or input/output -- refers to the interface between a computer and the rest of the world, or between a single program and the rest of the computer. It is such a crucial element of any computer system that the bulk of any I/O is actually built into the operating system. Individual programs generally have most of their work done for them.

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

NIO has the same role and purpose as original I/O, but it uses a different metaphor --block I/O. As you will learn in this tutorial, block I/O can be a lot more efficient than stream I/O.

Why NIO?

NIO was created to allow Java programmers 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 operating system, thus allowing for a great increase in speed.

Streams versus blocks

The most important distinction between the original I/O library (found injava.io.*) and NIO has to do with how data is packaged and transmitted. As previously mentioned, original I/O deals with data in streams, whereas NIO deals with data in blocks.

Astream-orientedI/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 is very easy to create filters for streamed data. It is also relatively simply to chain several filters together so that each one does its part in what amounts to a single, sophisticated processing mechanism. On the flip side, stream-oriented I/O is often rather slow.

Ablock-orientedI/O system deals with data in blocks. Each operation produces or consumes a block of data in one step. Processing data by the block can be much faster than processing it by the (streamed) byte. But block-oriented I/O lacks some of the elegance and simplicity of stream-oriented I/O.

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 of the classes in thejava.io.*package contain methods to read and write data in blocks, which leads to faster processing even in more stream-oriented systems.

It is also possible to use the NIO library to implement standard I/O functions. For example, you could easily use block I/O to move data one byte at a time. But as you will see, NIO also offers many advantages that are not available from the original I/O package.

 

Channels and buffers

Channels and buffers overview

Channels andBuffers are the central objects in NIO, and are used for just about every I/O operation.

Channels are analogous to streams in the original I/O package. All data that goes anywhere (or comes from anywhere) must pass through aChannelobject. ABufferis essentially a container object. All data that is sent to a channel must first be placed in a buffer; likewise, any data that is read from a channel is read into a buffer.

In this section, you will learn about working with channels and buffers in NIO.

What is a buffer?

ABufferis an object, which holds some data, that is to be written to or that has just been read from. The addition of theBufferobject in NIO marks one of the most significant differences between the new library and original I/O. In stream-oriented I/O, you wrote data directly to, and read data directly from,Streamobjects.

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, you are pulling it out of the buffer.

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

Kinds of buffers

The most commonly used kind of buffer is theByteBuffer. AByteBufferallows get/set operations (that is, the getting and setting of bytes) on its underlying byte array.

ByteBufferis not the only type of buffer in NIO. In fact, there is a buffer type for each of the primitive Java *:

ByteBuffer

CharBuffer

ShortBuffer

IntBuffer

LongBuffer

FloatBuffer

DoubleBuffer

Each of theBufferclasses is an instance of theBufferinterface. With the exception ofByteBuffer, each one has the exact same operations, differing only in the type of data it deals with. BecauseByteBufferis used for most standard I/O operations it has all of the shared buffer operations as well as some that are unique.

You may want to take a moment now to run the UseFloatBuffer.java, which contains an example of typed buffers in action.

What is a channel?

AChannelis 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.

As previously mentioned, all data is handled throughBufferobjects. You never write a byte directly to a channel; instead you write to a buffer containing one or more bytes. Likewise, you don't read a byte directly from a channel; you read from a channel into a buffer, and then get the bytes from the buffer.

Kinds of channels

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

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

 

From theory to practice: Reading and writing in NIO

NIO overview

Reading and writing are the fundamental processes of I/O. Reading from a channel is simple: we simply create a buffer and then ask a channel to read data into it. Writing is also fairly simply: we create a buffer, fill it with data, and then ask a channel to write from it.

In this section, we'll learn a little bit about reading and writing data in Java programs. We'll go over the main components of NIO (buffers, channels, and some related methods) and see how they interact for reading and writing. In the sections that follow, we will look at each of these components and interactions in more detail.

Reading from a file

For our first exercise, we'll read some data from a file. If we were using original I/O, we would simply create aFileInputStreamand read from that. In NIO, however, things work a little differently: we first get aChannelobject from theFileInputStream, 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 readdirectlyfrom a channel. Since all data ultimately resides in the buffer, you read from a channel into a buffer.

So reading from a file involves three steps: (1) getting theChannelfromFileInputStream; (2) creating theBuffer; and (3) reading from theChannelinto theBuffer.

Now, let's see how this works.

Three easy steps

Our first step is to get a channel. We get the channel from theFileInputStream:

FileInputStream fin = new FileInputStream( "readandshow.txt" );

FileChannel fc = fin.getChannel();

The next step is to create a buffer:

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

And, finally, we need to read from the channel into the buffer, as shown here:

fc.read( buffer );

You'll notice that we didn't need to tell the channelhow muchto read into the buffer. Each buffer has a sophisticated internal accounting system that keeps track of how much data has been read and how much room there is for more data. We'll talk more about the buffer accounting system in theBuffer internals overview.

Writing to a file

Writing to a file in NIO is similar to reading from one. We start by getting a channel from aFileOutputStream:

FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );

FileChannel fc = fout.getChannel();

Our next step is to create a buffer and put some data in it -- in this case, the data will be taken from an array calledmessagewhich contains the ASCII bytes for the string "Some bytes." (Thebuffer.flip()andbuffer.put()calls will be explained later in the tutorial.)

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

for (int i=0; i<message.length; ++i) {

buffer.put( message[i] );

}

buffer.flip();

Our final step is to write to the buffer:

fc.write( buffer );

Notice that once again we did not need to tell the channel how much data we wanted to write. The buffer's internal accounting system keeps track of how much data it contains and how much is left to be written.

Reading and writing together

Next we'll see what happens when we combine reading and writing. We'll base this exercise on a simple program called CopyFile.java, which copies all the data from one file to another one. CopyFile.java carries out three basic operations: it first creates aBuffer, then reads data from the source file into this buffer, and then writes the buffer to the destination file. The program repeats -- read, write, read, write -- until the source file is exhausted.

The CopyFile program will let you see how we check the status of an operation, as well as how we use theclear()andflip()methods to reset the buffer and prepare it to have newly read data written to another channel.

Running the CopyFile example

Because the buffer tracks its own data, the inner loop of the CopyFile program is very simple, as shown below:

fcin.read( buffer );

fcout.write( buffer );

The first line reads data into the buffer from the input channel,fcin, and the second line writes the data to the output channel,fcout.

Checking the status

Our next step is to check to see when we're done copying. We're done when there's no more data, and we can tell this when theread()method returns-1, as shown below:

int r = fcin.read( buffer );

if (r==-1) {

break;

}

Resetting the buffer

And, finally, we call theclear()method before we read into a buffer from the input channel. Likewise, we call theflip()method before we write a buffer to the output channel, as shown below:

buffer.clear();

int r = fcin.read( buffer );

if (r==-1) {

break;

}

buffer.flip();

fcout.write( buffer );

Theclear()method resets the buffer, making it ready to have data read into it. Theflip()method prepares the buffer to have the newly-read data written to another channel.

分享好友

分享这个小栈给你的朋友们,一起进步吧。

JAVA玩具小屋
创建时间:2019-08-16 16:54:49
分享程序开发方面的小经验,思考一些比较简单易懂的技术问题
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • Yios5092
    栈主

小栈成员

查看更多
  • 栈栈
  • coyan
  • 25minutes
  • ?
戳我,来吐槽~