﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-I am Thinking !-文章分类-Core Java</title><link>http://www.blogjava.net/Juizes361/category/42138.html</link><description>路漫漫兮其修远矣,吾将上下而求索!</description><language>zh-cn</language><lastBuildDate>Tue, 20 Oct 2009 14:29:37 GMT</lastBuildDate><pubDate>Tue, 20 Oct 2009 14:29:37 GMT</pubDate><ttl>60</ttl><item><title>Java new I/O 的使用</title><link>http://www.blogjava.net/Juizes361/articles/298794.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Mon, 19 Oct 2009 00:33:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/298794.html</guid><wfw:comment>http://www.blogjava.net/Juizes361/comments/298794.html</wfw:comment><comments>http://www.blogjava.net/Juizes361/articles/298794.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Juizes361/comments/commentRss/298794.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Juizes361/services/trackbacks/298794.html</trackback:ping><description><![CDATA[<span style="font-family: Comic Sans MS;"><span style="font-size: 10pt;"><span id="ArticleContent1_ArticleContent1_lblContent">
<p>NIO的使用</p>
<p>导读<br />
&nbsp;J2SE1.4以上版本中发布了全新的I/O类库。本文将通过一些实例来简单介绍NIO库提供的一些新特性：非阻塞I/O，字符转换，缓冲以及通道。</p>
<p>一.&nbsp;介绍NIO<br />
NIO包（java.nio.*）引入了四个关键的抽象数据类型，它们共同解决传统的I/O类中的一些问题。<br />
1．&nbsp;Buffer：它是包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作。<br />
2．&nbsp;Charset：它提供Unicode字符串影射到字节序列以及逆影射的操作。<br />
3．&nbsp;Channels：包含socket，file和pipe三种管道，它实际上是双向交流的通道。<br />
4．&nbsp;Selector：它将多元异步I/O操作集中到一个或多个线程中（它可以被看成是Unix中select（）函数或Win32中WaitForSingleEvent（）函数的面向对象版本）。<br />
二.&nbsp;回顾传统<br />
在介绍NIO之前，有必要了解传统的I/O操作的方式。以网络应用为例，传统方式需要监听一个ServerSocket，接受请求的连接为其提供服务（服务通常包括了处理请求并发送响应）图一是服务器的生命周期图，其中标有粗黑线条的部分表明会发生I/O阻塞。<br />
&nbsp;<img alt="" src="http://dev.csdn.net/Develop/ArticleImages/22/22063/CSDN_Dev_Image_2003-11-102336310.gif" align="baseline" border="0" hspace="0" /><br />
&nbsp;&nbsp; 图一<br />
可以分析创建服务器的每个具体步骤。首先创建ServerSocket<br />
&nbsp;ServerSocket server=new ServerSocket（10000）；<br />
然后接受新的连接请求 <br />
&nbsp;Socket newConnection=server.accept（）；<br />
对于accept方法的调用将造成阻塞，直到ServerSocket接受到一个连接请求为止。一旦连接请求被接受，服务器可以读客户socket中的请求。<br />
InputStream in = newConnection.getInputStream();<br />
InputStreamReader reader = new InputStreamReader(in);<br />
BufferedReader buffer = new BufferedReader(reader);<br />
Request request = new Request();<br />
while(!request.isComplete()) {<br />
&nbsp; String line = buffer.readLine();<br />
&nbsp; request.addLine(line);<br />
}<br />
这
样的操作有两个问题，首先BufferedReader类的readLine（）方法在其缓冲区未满时会造成线程阻塞，只有一定数据填满了缓冲区或者客户
关闭了套接字，方法才会返回。其次，它回产生大量的垃圾，BufferedReader创建了缓冲区来从客户套接字读入数据，但是同样创建了一些字符串存
储这些数据。虽然BufferedReader内部提供了StringBuffer处理这一问题，但是所有的String很快变成了垃圾需要回收。<br />
同样的问题在发送响应代码中也存在<br />
Response response = request.generateResponse();<br />
OutputStream out = newConnection.getOutputStream();<br />
InputStream in = response.getInputStream()；<br />
int ch；<br />
while(-1 != (ch = in.read())) {<br />
&nbsp; out.write(ch);<br />
}<br />
newConnection.close();<br />
类似的，读写操作被阻塞而且向流中一次写入一个字符会造成效率低下，所以应该使用缓冲区，但是一旦使用缓冲，流又会产生更多的垃圾。<br />
传统的解决方法<br />
&nbsp;通常在Java中处理阻塞I/O要用到线程（大量的线程）。一般是实现一个线程池用来处理请求，如图二<br />
&nbsp; <img alt="" src="http://dev.csdn.net/Develop/ArticleImages/22/22063/CSDN_Dev_Image_2003-11-102336312.gif" align="baseline" border="0" hspace="0" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;图二<br />
线程使得服务器可以处理多个连接，但是它们也同样引发了许多问题。每个线程拥有自己的栈空间并且占用一些CPU时间，耗费很大，而且很多时间是浪费在阻塞的I/O操作上，没有有效的利用CPU。<br />
三.&nbsp;新I/O<br />
1．&nbsp;Buffer<br />
传统的I/O不断的浪费对象资源（通常是String）。新I/O通过使用Buffer读写数据避免了资源浪费。Buffer对象是线性的，有序的数据集合，它根据其类别只包含唯一的数据类型。<br />
java.nio.Buffer&nbsp;类描述&nbsp;<br />
java.nio.ByteBuffer&nbsp;包含字节类型。 可以从ReadableByteChannel中读在&nbsp;&nbsp;&nbsp; WritableByteChannel中写&nbsp;<br />
java.nio.MappedByteBuffer&nbsp;包含字节类型，直接在内存某一区域映射&nbsp;<br />
java.nio.CharBuffer&nbsp;包含字符类型，不能写入通道&nbsp;<br />
java.nio.DoubleBuffer&nbsp;包含double类型，不能写入通道&nbsp;<br />
java.nio.FloatBuffer&nbsp;包含float类型&nbsp;<br />
java.nio.IntBuffer&nbsp;包含int类型&nbsp;<br />
java.nio.LongBuffer&nbsp;包含long类型&nbsp;<br />
java.nio.ShortBuffer&nbsp;包含short类型&nbsp;<br />
可
以通过调用allocate(int capacity)方法或者allocateDirect(int
capacity)方法分配一个Buffer。特别的，你可以创建MappedBytesBuffer通过调用FileChannel.map(int
mode,long position,int
size)。直接（direct）buffer在内存中分配一段连续的块并使用本地访问方法读写数据。非直接(nondirect)buffer通过使用
Java中的数组访问代码读写数据。有时候必须使用非直接缓冲例如使用任何的wrap方法（如ByteBuffer.wrap(byte[])）在
Java数组基础上创建buffer。<br />
2．&nbsp;字符编码<br />
向ByteBuffer中存放数据涉及到两个问题：字节的顺序和字符转换。ByteBuffer内部通过ByteOrder类处理了字节顺序问题，但是并没有处理字符转换。事实上，ByteBuffer没有提供方法读写String。<br />
&nbsp;Java.nio.charset.Charset处理了字符转换问题。它通过构造CharsetEncoder和CharsetDecoder将字符序列转换成字节和逆转换。<br />
3．&nbsp;通道(Channel)<br />
你可能注意到现有的java.io类中没有一个能够读写Buffer类型，所以NIO中提供了Channel类来读写Buffer。通道可以认为是一种连接，可以是到特定设备，程序或者是网络的连接。通道的类等级结构图如下<br />
&nbsp;<img alt="" src="http://dev.csdn.net/Develop/ArticleImages/22/22063/CSDN_Dev_Image_2003-11-102336314.gif" align="baseline" border="0" hspace="0" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;图三<br />
&nbsp;图中ReadableByteChannel和WritableByteChannel分别用于读写。<br />
GatheringByteChannel可以从使用一次将多个Buffer中的数据写入通道，相反的，ScatteringByteChannel则可以一次将数据从通道读入多个Buffer中。你还可以设置通道使其为阻塞或非阻塞I/O操作服务。<br />
为了使通道能够同传统I/O类相容，Channel类提供了静态方法创建Stream或Reader<br />
4．&nbsp;Selector<br />
在
过去的阻塞I/O中，我们一般知道什么时候可以向stream中读或写，因为方法调用直到stream准备好时返回。但是使用非阻塞通道，我们需要一些方
法来知道什么时候通道准备好了。在NIO包中，设计Selector就是为了这个目的。SelectableChannel可以注册特定的事件，而不是在
事件发生时通知应用，通道跟踪事件。然后，当应用调用Selector上的任意一个selection方法时，它查看注册了的通道看是否有任何感兴趣的事
件发生。图四是selector和两个已注册的通道的例子<br />
&nbsp; <img alt="" src="http://dev.csdn.net/Develop/ArticleImages/22/22063/CSDN_Dev_Image_2003-11-102336316.gif" align="baseline" border="0" hspace="0" /></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;图四<br />
并不是所有的通道都支持所有的操作。SelectionKey类定义了所有可能的操作位，将要用两次。首先，当应用调
用SelectableChannel.register(Selector sel,int
op)方法注册通道时，它将所需操作作为第二个参数传递到方法中。然后，一旦SelectionKey被选中了，SelectionKey的
readyOps()方法返回所有通道支持操作的数位的和。SelectableChannel的validOps方法返回每个通道允许的操作。注册通道
不支持的操作将引发IllegalArgumentException异常。下表列出了SelectableChannel子类所支持的操作。<br />
&nbsp;&nbsp;<br />
ServerSocketChannel&nbsp;OP_ACCEPT&nbsp;<br />
SocketChannel&nbsp;OP_CONNECT, OP_READ, OP_WRITE&nbsp;<br />
DatagramChannel&nbsp;OP_READ, OP_WRITE&nbsp;<br />
Pipe.SourceChannel&nbsp;OP_READ&nbsp;<br />
Pipe.SinkChannel&nbsp;OP_WRITE&nbsp;</p>
<p>四.&nbsp;举例说明<br />
1．&nbsp;简单网页内容下载<br />
这个例子非常简单，类SocketChannelReader使用SocketChannel来下载特定网页的HTML内容。<br />
package examples.nio;</p>
<p>import java.nio.ByteBuffer;<br />
import java.nio.channels.SocketChannel;<br />
import java.nio.charset.Charset;<br />
import java.net.InetSocketAddress;<br />
import java.io.IOException;</p>
<p>public class SocketChannelReader{<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; private Charset charset=Charset.forName("UTF-8");//创建UTF-8字符集<br />
&nbsp;&nbsp;&nbsp; private SocketChannel channel;</p>
<p>&nbsp;&nbsp;&nbsp; public void getHTMLContent(){<br />
&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connect();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendRequest();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; readResponse();<br />
&nbsp;&nbsp;&nbsp; }catch(IOException e){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(e.toString());<br />
&nbsp;&nbsp;&nbsp; }finally{<br />
&nbsp;&nbsp;&nbsp;&nbsp; if(channel!=null){<br />
&nbsp;&nbsp;&nbsp;&nbsp; try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; channel.close();<br />
&nbsp;&nbsp;}catch(IOException e){}<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private void connect()throws IOException{//连接到CSDN<br />
&nbsp;InetSocketAddress socketAddress=<br />
&nbsp;&nbsp;&nbsp;&nbsp; new InetSocketAddress("<a href="http://www.csdn.net%22,80/">www.csdn.net",80</a>);<br />
&nbsp;channel=SocketChannel.open(socketAddress);<br />
&nbsp;//使用工厂方法open创建一个channel并将它连接到指定地址上<br />
&nbsp;//相当与SocketChannel.open().connect(socketAddress);调用<br />
}</p>
<p>private void sendRequest()throws IOException{<br />
&nbsp;channel.write(charset.encode("GET "<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +"/document"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; +""r"n"r"n"));//发送GET请求到CSDN的文档中心<br />
&nbsp;//使用channel.write方法，它需要CharByte类型的参数，使用<br />
&nbsp;//Charset.encode(String)方法转换字符串。<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private void readResponse()throws IOException{//读取应答<br />
&nbsp;ByteBuffer buffer=ByteBuffer.allocate(1024);//创建1024字节的缓冲<br />
&nbsp;while(channel.read(buffer)!=-1){<br />
&nbsp;&nbsp;&nbsp;&nbsp; buffer.flip();//flip方法在读缓冲区字节操作之前调用。<br />
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(charset.decode(buffer));<br />
//使用Charset.decode方法将字节转换为字符串<br />
&nbsp;&nbsp;&nbsp;&nbsp; buffer.clear();//清空缓冲<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String [] args){<br />
&nbsp;new SocketChannelReader().getHTMLContent();<br />
&nbsp;&nbsp;&nbsp; }<br />
2．&nbsp;简单的加法服务器和客户机<br />
服务器代码<br />
package examples.nio;</p>
<p>import java.nio.ByteBuffer;<br />
import java.nio.IntBuffer;<br />
import java.nio.channels.ServerSocketChannel;<br />
import java.nio.channels.SocketChannel;<br />
import java.net.InetSocketAddress;<br />
import java.io.IOException;</p>
<p>/**<br />
&nbsp;* SumServer.java<br />
&nbsp;*<br />
&nbsp;*<br />
&nbsp;* Created: Thu Nov 06 11:41:52 2003<br />
&nbsp;*<br />
&nbsp;* @author starchu1981<br />
&nbsp;* @version 1.0<br />
&nbsp;*/<br />
public class SumServer {</p>
<p>&nbsp;&nbsp;&nbsp; private ByteBuffer _buffer=ByteBuffer.allocate(8);<br />
&nbsp;&nbsp;&nbsp; private IntBuffer _intBuffer=_buffer.asIntBuffer();<br />
&nbsp;&nbsp;&nbsp; private SocketChannel _clientChannel=null;<br />
&nbsp;&nbsp;&nbsp; private ServerSocketChannel _serverChannel=null;</p>
<p>&nbsp;&nbsp;&nbsp; public void start(){<br />
&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;&nbsp; openChannel();<br />
&nbsp;&nbsp;&nbsp;&nbsp; waitForConnection();<br />
&nbsp;}catch(IOException e){<br />
&nbsp;&nbsp;&nbsp;&nbsp; System.err.println(e.toString());<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private void openChannel()throws IOException{<br />
&nbsp;_serverChannel=ServerSocketChannel.open();<br />
&nbsp;_serverChannel.socket().bind(new InetSocketAddress(10000));<br />
&nbsp;System.out.println("服务器通道已经打开");<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private void waitForConnection()throws IOException{<br />
&nbsp;while(true){<br />
&nbsp;&nbsp;&nbsp;&nbsp; _clientChannel=_serverChannel.accept();<br />
&nbsp;&nbsp;&nbsp;&nbsp; if(_clientChannel!=null){<br />
System.out.println("新的连接加入");<br />
processRequest();<br />
_clientChannel.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private void processRequest()throws IOException{<br />
&nbsp;_buffer.clear();<br />
&nbsp;_clientChannel.read(_buffer);<br />
&nbsp;int result=_intBuffer.get(0)+_intBuffer.get(1);<br />
&nbsp;_buffer.flip();<br />
&nbsp;_buffer.clear();<br />
&nbsp;_intBuffer.put(0,result);<br />
&nbsp;_clientChannel.write(_buffer);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String [] args){<br />
&nbsp;new SumServer().start();<br />
&nbsp;&nbsp;&nbsp; }<br />
} // SumServer<br />
客户代码<br />
package examples.nio;</p>
<p>import java.nio.ByteBuffer;<br />
import java.nio.IntBuffer;<br />
import java.nio.channels.SocketChannel;<br />
import java.net.InetSocketAddress;<br />
import java.io.IOException;</p>
<p>/**<br />
&nbsp;* SumClient.java<br />
&nbsp;*<br />
&nbsp;*<br />
&nbsp;* Created: Thu Nov 06 11:26:06 2003<br />
&nbsp;*<br />
&nbsp;* @author starchu1981<br />
&nbsp;* @version 1.0<br />
&nbsp;*/<br />
public class SumClient {</p>
<p>&nbsp;&nbsp;&nbsp; private ByteBuffer _buffer=ByteBuffer.allocate(8);<br />
&nbsp;&nbsp;&nbsp; private IntBuffer _intBuffer;<br />
&nbsp;&nbsp;&nbsp; private SocketChannel _channel;</p>
<p>&nbsp;&nbsp;&nbsp; public SumClient() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _intBuffer=_buffer.asIntBuffer();<br />
&nbsp;&nbsp;&nbsp; } // SumClient constructor<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public int getSum(int first,int second){<br />
&nbsp;int result=0;<br />
&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;&nbsp; _channel=connect();<br />
&nbsp;&nbsp;&nbsp;&nbsp; sendSumRequest(first,second);<br />
&nbsp;&nbsp;&nbsp;&nbsp; result=receiveResponse();<br />
&nbsp;}catch(IOException e){System.err.println(e.toString());<br />
&nbsp;}finally{<br />
&nbsp;&nbsp;&nbsp;&nbsp; if(_channel!=null){<br />
&nbsp;&nbsp;try{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _channel.close();<br />
&nbsp;&nbsp;}catch(IOException e){}<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;}<br />
&nbsp;return result;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; private SocketChannel connect()throws IOException{<br />
&nbsp;InetSocketAddress socketAddress=<br />
&nbsp;&nbsp;&nbsp;&nbsp; new InetSocketAddress("localhost",10000);<br />
&nbsp;return SocketChannel.open(socketAddress);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; private void sendSumRequest(int first,int second)throws IOException{<br />
&nbsp;_buffer.clear();<br />
&nbsp;_intBuffer.put(0,first);<br />
&nbsp;_intBuffer.put(1,second);<br />
&nbsp;_channel.write(_buffer);<br />
&nbsp;System.out.println("发送加法请求 "+first+"+"+second);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; private int receiveResponse()throws IOException{<br />
&nbsp;_buffer.clear();<br />
&nbsp;_channel.read(_buffer);<br />
&nbsp;return _intBuffer.get(0);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String [] args){<br />
&nbsp;SumClient sumClient=new SumClient();<br />
&nbsp;System.out.println("加法结果为 :"+sumClient.getSum(100,324));<br />
&nbsp;&nbsp;&nbsp; }<br />
} // SumClient<br />
3．&nbsp;非阻塞的加法服务器<br />
首先在openChannel方法中加入语句<br />
&nbsp;_serverChannel.configureBlocking(false);//设置成为非阻塞模式</p>
<p>重写WaitForConnection方法的代码如下，使用非阻塞方式<br />
private void waitForConnection()throws IOException{<br />
&nbsp;Selector acceptSelector = SelectorProvider.provider().openSelector();&nbsp;</p>
<p>&nbsp;/*在服务器套接字上注册selector并设置为接受accept方法的通知。<br />
&nbsp;这就告诉Selector，套接字想要在accept操作发生时被放在ready表<br />
&nbsp;上，因此，允许多元非阻塞I/O发生。*/<br />
&nbsp;SelectionKey acceptKey = ssc.register(acceptSelector, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SelectionKey.OP_ACCEPT);<br />
&nbsp;int keysAdded = 0;<br />
&nbsp;<br />
&nbsp;/*select方法在任何上面注册了的操作发生时返回*/<br />
&nbsp;while ((keysAdded = acceptSelector.select()) &gt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp; // 某客户已经准备好可以进行I/O操作了，获取其ready键集合<br />
&nbsp;&nbsp;&nbsp;&nbsp; Set readyKeys = acceptSelector.selectedKeys();<br />
&nbsp;&nbsp;&nbsp;&nbsp; Iterator i = readyKeys.iterator();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; // 遍历ready键集合，并处理加法请求<br />
&nbsp;&nbsp;&nbsp;&nbsp; while (i.hasNext()) {<br />
&nbsp;&nbsp;SelectionKey sk = (SelectionKey)i.next();<br />
&nbsp;&nbsp;i.remove();<br />
&nbsp;&nbsp;ServerSocketChannel nextReady = <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (ServerSocketChannel)sk.channel();<br />
&nbsp;&nbsp;// 接受加法请求并处理它<br />
&nbsp;&nbsp;_clientSocket = nextReady.accept().socket();<br />
&nbsp;&nbsp;&nbsp;processRequest();<br />
&nbsp;&nbsp;&nbsp;_clientSocket.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>参考资料<br />
1．&nbsp;&lt;Master Merlin's new I/O classes&gt;&nbsp;&nbsp; From &lt;<a href="http://www.javawordl.com/">http://www.javawordl.com/</a>&gt;<br />
2．&nbsp;J2SE1.4.2 API Specification From &lt;<a href="http://java.sun.com/">http://java.sun.com/</a>&gt;<br />
3．&nbsp;&lt;Working with SocketChannels&gt; From &lt;<a href="http://developer.java.sun.com/developer">http://developer.java.sun.com/developer</a>&gt;<br />
&nbsp;4.&nbsp;&nbsp; NIO Examples From &lt;<a href="http://java.sun.com/">http://java.sun.com/</a>&gt;</p>
</span>
</span></span>
<img src ="http://www.blogjava.net/Juizes361/aggbug/298794.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-10-19 08:33 <a href="http://www.blogjava.net/Juizes361/articles/298794.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>System.out 和 System.err</title><link>http://www.blogjava.net/Juizes361/articles/263681.html</link><dc:creator>残叶舞风</dc:creator><author>残叶舞风</author><pubDate>Fri, 03 Apr 2009 01:51:00 GMT</pubDate><guid>http://www.blogjava.net/Juizes361/articles/263681.html</guid><description><![CDATA[<span style="font-size: 10pt; font-family: Comic Sans MS">今天查看代码时遇到了System.err,但是平时使用的并不多,以下是我查到的资料出处不详,给大家做个参考,在此对作者给予感谢:<br />
<br />
资料一:<br />
<br />
System.out leads the output to the standard output stream (normally mapped to the console screen). System.err leads the output to the standard error stream (and, by default to the console, as well). The idea behind having these two is that the standard output should be used for regular program output, and standard error should be used for error messages.<br />
<br />
<br />
Both the streams can be redirected to different destinations. If it is desired to redirect the output to an output file and error messages to a different log file, than on UNIX it can be done as follows:<br />
<pre><code>java MyClass &gt; output.log 2&gt;error.log<br />
</code></pre>
This causes the regular output (using System.out) to be stored in output.log and error messages (using System.err) to be stored in error.log.<br />
<br />
<br />
If you have put error messages in your program, but you don't want to see them, the technique given below can be used to do it:<br />
<pre><code>Java MyClass 2&gt; /null<br />
</code></pre>
This redirects the System.err messages to /null, so no error messages appear on the screen, but the normal program output can still be seen.<br />
<br />
<br />
资料二:<br />
<br />
大多数操作系统都有三个标准文件描述符：标准输入，标准输出，标准出错。<br />
<br />
三个操作系统的文件描述符映射到编程语言的标准库中，往往加了一层包装，但是名字通常还是叫标准输入，标准输出，标准出错。<br />
<br />
在其它语言中的一般写法是：stdin，stdout，stderr（有的语言里大写，有的语言里小写）。对应Java中的System.in，System.out，System.err。<br />
<br />
在语言层面的实现<span style="color: red">三个文件描述符都是可以重定向的</span>（只要你想）。但是一般而言，如果你在unix&nbsp;shell或windows&nbsp;command&nbsp;line中使用管道或重定向，则只是针对标准输入和输出。<br />
<br />
另外，标准输出和标准出错的一个区别是，<span style="color: red">标准输出往往是带缓存的，而标准出错没有缓存</span>（默认设置，可以改）。所以如果你用标准出错打印出来的东西可以马上显示在屏幕，而标准输出打印出来的东西可能要再积累几个字符才能一起打印出来。如果你在应用中混用标准输出和标准出错就可能看到这个问题。<br />
<br />
总的来说，System.out用于正常的输出，也就是程序真正想输出的内容。而System.err用于出错信息的输出，也就是你本来不期待看到的东西。<br />
<br />
因此，System.err打出来的信息常常会跑到System.out信息的前面去。<br />
<br />
<br />
</span><br />
<img src ="http://www.blogjava.net/Juizes361/aggbug/263681.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Juizes361/" target="_blank">残叶舞风</a> 2009-04-03 09:51 <a href="http://www.blogjava.net/Juizes361/articles/263681.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>