您的位置:首页 > 编程语言 > Java开发

java nio 常见的nio类, nio 写文件方法, nio 比io 的优势

2016-06-24 16:12 435 查看
1..nio是同步非阻塞的意思, 以前的IO 都是阻塞IO, nio是非阻塞IO

2..阻塞非阻塞意思就是,  阻塞是线程一直等,  非阻塞是线程不等.   非阻塞就是来连接我不创建线程, 直到你来IO数据的请求, 即http 包, 我才创建线程, 如代码aaa处  

    int n = selector.select( ) 就是同步非阻塞的意思 , n代表IO请求的数量, 你来请求之前,我可以做我的事, 不是阻塞等, 你来请求之后即n>0, 我也照样可以做自己的事,

    爱什么时候处理IO就什么时候处理IO     即非阻塞就是你来IO我才创建线程去处理

nio 代码如下:

package NIO;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Date;
import java.util.Iterator;
/**
*
* NIO (2) Chanel,chanel 就是通道,ByteBuffer俗称缓冲器,ByteBuffer 底层用byte[]数组存储实现的
* 以下函数注释中括号的数字对应如下链接中的章节,参考:http://ifeve.com/file-channel/
*
* NIO 和IO 的区别:
* nio 快,io 慢.(13)unBlockReadTest()函数
* nio 不阻塞, io阻塞, 未看出
* nio 可以从文件的指定位置读/写, io做不到  (14)updateFile()函数
*
* @author jaloli
*
*/

public class FileChanelTest {
//(2,3)
public static void writeAndReadChanel() throws IOException {  //write buffer,read buffer
RandomAccessFile aFile = new RandomAccessFile("nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read " + bytesRead);
buf.flip();//翻转缓冲,使其由能写变成能读
System.out.println("初始 position :" +buf.position() + " limit : " + buf.limit() );
while(buf.hasRemaining()){
System.out.print( buf.position() + ":" + (char) buf.get() + " ");
}
buf.clear();
bytesRead = inChannel.read(buf);
System.out.println("\nRead " + bytesRead);
}
aFile.close();
}
//(4)分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中
//聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel
public static void writeFileChanel() throws IOException {  //write chanel
RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer body = ByteBuffer.allocate(6);
ByteBuffer header = ByteBuffer.allocate(120000000);
header.put(new byte[]{65,66,67,68,69,70});
body.put(new byte[]{71,72,73,74,75,76});
header.flip();
body.flip();
//		System.out.println(header.getChar());
ByteBuffer[] bufferArray = {header,body};//这里就是读buffer
inChannel.write(bufferArray);
aFile.close();
}

//(12)非阻塞测试, 如151行注释, 非block 并未发生,存疑
public static void unBlockWriteTest() throws IOException {  //write chanel
RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer body = ByteBuffer.allocate(6);
ByteBuffer header = ByteBuffer.allocate(120000000);
byte[] needWriteByte = new byte[10000000];
byte[] needWriteByte1 = new byte[10000000];
byte[] needWriteByte2 = new byte[10000000];
byte[] needWriteByte3 = new byte[10000000];
byte[] needWriteByte4 = new byte[10000000];
byte[] needWriteByte5 = new byte[10000000];
byte[] needWriteByte6 = new byte[10000000];
byte[] needWriteByte7 = new byte[10000000];
byte[] needWriteByte8 = new byte[10000000];
byte[] needWriteByte9 = new byte[10000000];
byte[] needWriteByte10 = new byte[10000000];
byte[] needWriteByte11 = new byte[10000000];
for(int i=0;i<10000000;i++){//10000000
needWriteByte[i] = 1;
needWriteByte1[i] = 1;
needWriteByte2[i] = 1;
needWriteByte3[i] = 1;
needWriteByte4[i] = 1;
needWriteByte5[i] = 1;
needWriteByte6[i] = 1;
needWriteByte7[i] = 1;
needWriteByte8[i] = 1;
needWriteByte9[i] = 1;
needWriteByte10[i] = 1;
needWriteByte11[i] = 1;
}
header.put(needWriteByte);
header.put(needWriteByte1);
header.put(needWriteByte2);
header.put(needWriteByte3);
header.put(needWriteByte4);
header.put(needWriteByte5);
header.put(needWriteByte6);
header.put(needWriteByte7);
header.put(needWriteByte8);
header.put(needWriteByte9);
header.put(needWriteByte10);
header.put(needWriteByte11);
body.put(new byte[]{71,72,73,74,75,76});//
header.flip();
body.flip();
ByteBuffer[] bufferArray = {header,body};//   这里就是读buffer
inChannel.write(bufferArray); //  这个会写117M的文件, 这个写的时候,卡住一下,写好后,再继续走下面的代码
System.out.println("gggggggggggggggggggg");
aFile.close();
}

//(13)nio 非阻塞读, 没看出来,但是看出来 nio 性能优于io
public static void unBlockReadTest() throws IOException {  //write chanel
RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
int _5M = 1024*1024*5;
ByteBuffer dst = ByteBuffer.allocateDirect(1);//_5M
Date date = new Date();
System.out.println(String.valueOf(date.getTime()));
for(int i=0;i<10000000;i++){
inChannel.read(dst);//这个就是一直在读文件的dst 个字节
//			inChannel.position(3);
//			System.out.println(inChannel.position());//以上两句有效,但是对read()方法无作用
//			System.out.println(byteBufferToString(dst));
}
System.out.println(String.valueOf(date.getTime()));//以上读完耗时忽略,是因为NIO面向的是data chunks,而java.io基本上是面向byte

FileInputStream fr = new FileInputStream("nio-data1.txt");
BufferedInputStream bis = new BufferedInputStream(fr);
byte[] bytes = new byte[_5M];
System.out.println(String.valueOf(date.getTime()));
for(int i=0;i<10000000;i++) {
System.out.println(bis.read(bytes));
}
System.out.println(String.valueOf(date.getTime()));//java io 读完耗时特别长,原因就是链接http://justjavac.iteye.com/blog/1998207 说的io 用吸管吸os给的一盆水
}

//(14)nio 可以从文件指定位置写, 从文件指定位置读, io 做不到
public static void updateFile() throws IOException {
RandomAccessFile aFile = new RandomAccessFile("nio-data1.txt", "rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer needInsert = ByteBuffer.allocate(216);
ByteBuffer readIn = ByteBuffer.allocate(216);
needInsert.put("好".getBytes());
needInsert.flip();//如果不加这句则无论字母汉字都是出乱码,因为后面的不可预知的字符会以utf-8等编码去解析
inChannel.write(needInsert,3);//文件指定位置插入,源文件是 gegbbbbbbbbbwqfewq, 文件插入指定位置插入字符后变为  geg好bbbbbbbbbwqfewq
inChannel.read(readIn, 3);//从指定位置读       我bbbbbbwqfewq
readIn.flip();
System.out.println(byteBufferToString(readIn));
aFile.close();
}

//(5)transferFrom / transferTo
public static void transferFromTest() {

}

//(6)selector 不懂干啥的,  浏览器中输入localhost:30/fdg 可以一直打印对象.代码参考:http://www.cnblogs.com/gaotianle/p/3325451.html
public static void selectorTest() throws IOException {
int port = 30;
ServerSocketChannel serverChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverChannel.socket();
Selector selector = Selector.open();
serverSocket.bind(new InetSocketAddress(port));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);// 第二个参数是四种事件。这样serverChannel
// 作为一个channel
// 就注册到selector
// 上了
while (true) {//<strong>selector 负责监听channel上有无数据,监听到后,channel 去read()拿数据</strong>
int n = selector.select();//这里就是同步非阻塞, 也就是nio同步非阻塞的意思所在aaa
if (n == 0) {             //但是这里非阻塞虽然不用一直等IO请求, 但也在一直轮询, 所以比较耗费资源, 因此出现aio
continue; // nothing to do,其实这里可以做别的事,即非阻塞, 做一定的事后, 可以再selector.select() 判断有无IO请求到来,而不是一来个连接,就创建线程等待IO.
}
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {							//当然这里如果来了IO请求, 那么本例没创建线程,而是用当前线程去处理IO数据
SelectionKey key = (SelectionKey) it.next();
if (key.isAcceptable()) {
ServerSocketChannel serverchanel = (ServerSocketChannel) key.channel();
SocketChannel channel = serverchanel.accept();
if (channel == null) {
;// handle code, could happen
}
channel.configureBlocking(false);// selector.select
// 来选择已经注册的多个通道之一
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel channel = (SocketChannel) key.channel(); // 通过selector
// 的key
// 拿到channel
ByteBuffer buffer = ByteBuffer.allocate(48);// channel
// 的东西落到buffer
// 里,进而转化成byte,转化成string
int read = channel.read(buffer);
byte[] data = buffer.array();
String message = new String(data);
System.out.println("接收到的消息是: " + message);
} else if (key.isWritable()) {

} else if (key.isConnectable()) {
SelectableChannel chanel = key.channel();
System.out.println(chanel.toString());
}
it.remove();
}
}
}
//ByteBuffer to String
private static String byteBufferToString(ByteBuffer buf) {
CharBuffer charBuffer = null;
try{
if(buf.position() != 0)
buf.flip();   //flip() 函数是让  ByteBuffer 对象的position 变为0. 这里不flip()打不出来ByteBuffer 缓冲区的数据
Charset charset = Charset.forName("UTF-8");
CharsetDecoder decoder = charset.newDecoder();
charBuffer = decoder.decode(buf);
return charBuffer.toString();
} catch(Exception ex) {
ex.printStackTrace();
}
return null;
}

//(7)FileChannel
public static void fileChannelTest() throws IOException{
//FileChannel 读数据
RandomAccessFile rFile = new RandomAccessFile("D:/xiecheng/EclipseWorkingspace/WorkspaceLearning/jsp_api/src/FileChannelReadTest.txt", "rw");
FileChannel inChannel = rFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);
String readFileContent = byteBufferToString(buf);
System.out.println("读文件结果为: "+readFileContent);

//FileChannel 写数据
RandomAccessFile wFile = new RandomAccessFile("D:/xiecheng/EclipseWorkingspace/WorkspaceLearning/jsp_api/src/FileChannelWriteTest.txt", "rw");
FileChannel outChannel = wFile.getChannel();
String needWrite = "我被写入文件aaa";
ByteBuffer needWriteBuf = ByteBuffer.allocate(48);
needWriteBuf.clear();
needWriteBuf.put(needWrite.getBytes());
needWriteBuf.flip();
while(needWriteBuf.hasRemaining()) {
outChannel.write(needWriteBuf);
}
System.out.println("写文件结果请看文件本身,写的内容是:"+needWrite);
}

//(8)SocketChannel如上面(6)

//(10)DatagramChannel实现UDP传输,使用如下两个函数,  参考http://www.cnblogs.com/bronte/articles/1966607.html
public static void socketChannelServerTest() throws IOException{
DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9991));
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);
String readFileContent = byteBufferToString(buf);
System.out.println("SocketChannel 接收的结果为: "+readFileContent);
}
//这个客户端函数在另一个类中运行,方便查看客户端给服务端发的数据
public static void socketChannelClientTest() throws IOException{
DatagramChannel channel = DatagramChannel.open();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();
int bytesSent = channel.send(buf, new InetSocketAddress(9991));

}
//(11)Pipe
public static void pipeTest() throws IOException {
//写
Pipe pipe = Pipe.open();
Pipe.SinkChannel sinkChannel = pipe.sink();
String newData = "New String to write to file..." + System.currentTimeMillis();
ByteBuffer needBeWriteBuf = ByteBuffer.allocate(48);//此时needBeWriteBuf 这个ByteBuffer 的limit 值是0
needBeWriteBuf.clear();
needBeWriteBuf.put(newData.getBytes());
System.out.println("needBeWriteBuf 的postion 和 limit 分别是: "+needBeWriteBuf.position() +", "+ needBeWriteBuf.limit());
needBeWriteBuf.flip(); //position 设置为0,即顶头,读写公用一个position
while(needBeWriteBuf.hasRemaining()) { //这个一次可能写0个到多个,所以需要重复写
int byteWriteNum = sinkChannel.write(needBeWriteBuf);//write 之后,needBeWriteBuf 的position 就变成了43
System.out.println("往sinkChannel 写的数据字节数为:" + byteWriteNum + ", 写的数据为: " + newData);
}
//读
Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer needReadToBuf = ByteBuffer.allocate(48);
int byteReadNum = sourceChannel.read(needReadToBuf);
System.out.println("read 之后, postion is : "+needReadToBuf.position());  //read 一次, position 变为43
String sourceChannelContent = byteBufferToString(needReadToBuf);
System.out.println("sourceChannel 接收的结果长度为: " + byteReadNum +", sourceChannel 接收的结果为: "+sourceChannelContent);
}

//ByteBuffer 缓冲区
public static void byteBufferTest(){
ByteBuffer needBeWriteBuf = ByteBuffer.allocate(48);
needBeWriteBuf.clear();
needBeWriteBuf.put("我".getBytes());
needBeWriteBuf.put("我".getBytes());
needBeWriteBuf.put("我".getBytes());
//		needBeWriteBuf.clear(); //buffer.clear()  缓冲区清空了
needBeWriteBuf.put("你".getBytes()); //正常追加到缓冲区, 我我我你

String sourceChannelContent = byteBufferToString(needBeWriteBuf);
System.out.println("ByteBuffer 缓冲区内容是  is " + sourceChannelContent);
}

public static void main(String[] args) throws IOException {
//		writeAndReadChanel();
//		writeFileChanel();
//		selectorTest();
//		fileChannelTest();
//		socketChannelServerTest();
//		pipeTest();
//		byteBufferTest();
//		unBlockWriteTest();
//		unBlockReadTest();
updateFile();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: