# ä¸ãNIO
æ°çè¾å
¥/è¾åº (NIO) åºæ¯å¨ JDK 1.4 ä¸å¼å
¥çï¼å¼¥è¡¥äºåæ¥ç I/O çä¸è¶³ï¼æä¾äºé«éçãé¢ååç I/Oã
NIOæ ¸å¿ç»ä»¶:
- éé(Channels)
- ç¼å²åº(Buffers)
- éæ©å¨(Selectors)
## æµä¸å
I/O ä¸ NIO æéè¦çåºå«æ¯æ°æ®æå
åä¼ è¾çæ¹å¼ï¼I/O 以æµçæ¹å¼å¤çæ°æ®ï¼è NIO 以åçæ¹å¼å¤çæ°æ®ã
é¢åæµç I/O 䏿¬¡å¤çä¸ä¸ª**åè**æ°æ®ï¼ä¸ä¸ªè¾å
¥æµäº§çä¸ä¸ªåèæ°æ®ï¼ä¸ä¸ªè¾åºæµæ¶è´¹ä¸ä¸ªåèæ°æ®ã
为æµå¼æ°æ®åå»ºè¿æ»¤å¨é常容æï¼é¾æ¥å ä¸ªè¿æ»¤å¨ï¼ä»¥ä¾¿æ¯ä¸ªè¿æ»¤å¨åªè´è´£å¤æå¤çæºå¶çä¸é¨åãä¸å©çä¸é¢æ¯ï¼é¢åæµç I/O é常ç¸å½æ
¢ã
é¢ååç I/O 䏿¬¡å¤çä¸ä¸ª**æ°æ®å**ï¼æåå¤çæ°æ®æ¯ææµå¤çæ°æ®è¦å¿«å¾å¤ã
使¯é¢ååç I/O 缺å°ä¸äºé¢åæµç I/O æå
·æçä¼é
æ§åç®åæ§ã
I/O å
å NIO å·²ç»å¾å¥½å°éæäºï¼java.io.\* å·²ç»ä»¥ NIO 为åºç¡éæ°å®ç°äºï¼æä»¥ç°å¨å®å¯ä»¥å©ç¨ NIO çä¸äºç¹æ§ã
ä¾å¦ï¼java.io.\* å
ä¸çä¸äºç±»å
å«ä»¥åçå½¢å¼è¯»åæ°æ®çæ¹æ³ï¼è¿ä½¿å¾å³ä½¿å¨é¢åæµçç³»ç»ä¸ï¼å¤çé度ä¹ä¼æ´å¿«ã
## ééä¸ç¼å²åº
### 1. éé
éé Channel æ¯å¯¹å I/O å
ä¸çæµç模æï¼å¯ä»¥éè¿å®è¯»åååå
¥æ°æ®ã
éé䏿µçä¸åä¹å¤å¨äºï¼æµåªè½å¨ä¸ä¸ªæ¹åä¸ç§»å¨(ä¸ä¸ªæµå¿
é¡»æ¯ InputStream æè
OutputStream çåç±»)ï¼
èé鿝**åå**çï¼å¯ä»¥ç¨äºè¯»ãåæè
åæ¶ç¨äºè¯»åã
ééå
æ¬ä»¥ä¸ç±»åï¼
- FileChannelï¼ä»æä»¶ä¸è¯»åæ°æ®ï¼
- DatagramChannelï¼éè¿ UDP 读åç½ç»ä¸æ°æ®ï¼
- SocketChannelï¼éè¿ TCP 读åç½ç»ä¸æ°æ®ï¼
- ServerSocketChannelï¼å¯ä»¥ç嬿°è¿æ¥ç TCP è¿æ¥ï¼å¯¹æ¯ä¸ä¸ªæ°è¿æ¥çè¿æ¥é½ä¼å建ä¸ä¸ª SocketChannelã
### 2. ç¼å²åº
åéç»ä¸ä¸ªééçæææ°æ®é½å¿
é¡»é¦å
æ¾å°ç¼å²åºä¸ï¼åæ ·å°ï¼ä»ééä¸è¯»åç任使°æ®é½è¦å
读å°ç¼å²åºä¸ãä¹å°±æ¯è¯´ï¼ä¸ä¼ç´æ¥å¯¹ééè¿è¡è¯»åæ°æ®ï¼èæ¯è¦å
ç»è¿ç¼å²åºã
ç¼å²åºå®è´¨ä¸æ¯ä¸ä¸ªæ°ç»ï¼ä½å®ä¸ä»
ä»
æ¯ä¸ä¸ªæ°ç»ãç¼å²åºæä¾äºå¯¹æ°æ®çç»æå访é®ï¼èä¸è¿å¯ä»¥è·è¸ªç³»ç»ç读/åè¿ç¨ã
ç¼å²åºå
æ¬ä»¥ä¸ç±»åï¼
- ByteBuffer
- CharBuffer
- ShortBuffer
- IntBuffer
- LongBuffer
- FloatBuffer
- DoubleBuffer
## ç¼å²åºç¶æåé
- capacityï¼æå¤§å®¹éï¼
- positionï¼å½åå·²ç»è¯»åçåèæ°ï¼
- limitï¼è¿å¯ä»¥è¯»åçåèæ°ã
ç¶æåéçæ¹åè¿ç¨ä¸¾ä¾ï¼
â æ°å»ºä¸ä¸ªå¤§å°ä¸º 8 个åèçç¼å²åºï¼æ¤æ¶ position 为 0ï¼è limit = capacity = 8ãcapacity åéä¸ä¼æ¹åï¼ä¸é¢ç讨论ä¼å¿½ç¥å®ã
â¡ ä»è¾å
¥ééä¸è¯»å 5 个åèæ°æ®åå
¥ç¼å²åºä¸ï¼æ¤æ¶ position 为 5ï¼limit ä¿æä¸åã
⢠å¨å°ç¼å²åºçæ°æ®åå°è¾åºééä¹åï¼éè¦å
è°ç¨ flip() æ¹æ³ï¼è¿ä¸ªæ¹æ³å° limit 设置为å½å positionï¼å¹¶å° position 设置为 0ã
⣠ä»ç¼å²åºä¸å 4 个åèå°è¾åºç¼å²ä¸ï¼æ¤æ¶ position 设为 4ã
⤠æåéè¦è°ç¨ clear() æ¹æ³æ¥æ¸
空ç¼å²åºï¼æ¤æ¶ position å limit é½è¢«è®¾ç½®ä¸ºæåä½ç½®ã
## æä»¶ NIO å®ä¾
### FileChannelç使ç¨
1. å¼å¯FileChannel
2. ä»FileChannelè¯»åæ°æ®/åå
¥æ°æ®
3.å
³éFileChannel
```java
public class FileChannelDemo {
public static void main(String[] args) throws IOException {
//1.å建ä¸ä¸ªRandomAccessFileï¼éæºè®¿é®æä»¶ï¼å¯¹è±¡éè¿RandomAccessFile对象çgetChannel()æ¹æ³ã
RandomAccessFile raf=new RandomAccessFile("demo6.txt","rw");
FileChannel fc=raf.getChannel();
//使ç¨FileChannelçread()æ¹æ³è¯»åæ°æ®ï¼
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
int bys=fc.read(byteBuffer);
//使ç¨FileChannelçwrite()æ¹æ³åå
¥æ°æ®ï¼
ByteBuffer byteBuffer2=ByteBuffer.allocate(1024);
byteBuffer2.put("hello".getBytes());
fc.write(byteBuffer2);
//3.å
³éFileChannel
fc.close();
}
}
```
- 以ä¸å±ç¤ºäºä½¿ç¨ NIO å¿«éå¤å¶æä»¶çå®ä¾ï¼
```java
public class CopyFile {
public static void main(String[] args) throws IOException {
String srcFile="彿æ.mp4";
String destFile="demo3.mp4";
long start = System.currentTimeMillis();
//copyFile(srcFile,destFile); //å
±èæ¶ï¼75309毫ç§
//copyFile2(srcFile,destFile); //å
±èæ¶ï¼153毫ç§
//copyFile3(srcFile,destFile);//å
±èæ¶ï¼282毫ç§
//copyFile4(srcFile,destFile);//å
±èæ¶ï¼44毫ç§
copyFile5(srcFile,destFile);//å
±èæ¶ï¼å
±èæ¶ï¼113毫ç§
long end = System.currentTimeMillis();
System.out.println("å
±èæ¶ï¼" + (end - start) + "毫ç§");
}
/**
* åºæ¬åèæµä¸æ¬¡è¯»åä¸ä¸ªåè
*/
public static void copyFile(String srcFile,String destFile) throws IOException {
FileInputStream fis=new FileInputStream(srcFile);
FileOutputStream fos=new FileOutputStream(destFile);
int by=0;
while((by=fis.read())!=-1){
fos.write(by);
}
fis.close();
fos.close();
}
/**
* åºæ¬åèæµä¸æ¬¡è¯»åä¸ä¸ªåèæ°ç»
*/
public static void copyFile2(String srcFile,String destFile) throws IOException{
FileInputStream fis=new FileInputStream(srcFile);
FileOutputStream fos=new FileOutputStream(destFile);
int len=0;
byte[] bys=new byte[1024];
while((len=fis.read(bys))!=-1){
fos.write(bys,0,len);
}
fis.close();
fos.close();
}
/**
* 髿åèæµä¸æ¬¡è¯»åä¸ä¸ªåè
*/
public static void copyFile3(String srcFile,String destFile) throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile));
int by=0;
while((by=bis.read())!=-1){
bos.write(by);
}
bis.close();
bos.close();
}
/**
* 髿åèæµä¸æ¬¡è¯»åä¸ä¸ªåèæ°ç»
*/
public static void copyFile4(String srcFile,String destFile) throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(destFile));
int len=0;
byte[] bys=new byte[1024];
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close();
bos.close();
}
/**
* 使ç¨FileChannelå¤å¶æä»¶
*/
public static void copyFile5(String srcFile,String destFile) throws IOException{
FileInputStream fis=new FileInputStream(srcFile);
//è·åè¾å
¥åèæµçæä»¶éé
FileChannel fcin=fis.getChannel();
FileOutputStream fos=new FileOutputStream(destFile);
//è·åè¾åºåèæµçæä»¶éé
FileChannel fcout=fos.getChannel();
//为ç¼å²åºåé
1024 个åè
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while(true){
//ä»è¾å
¥ééä¸è¯»åæ°æ®å°ç¼å²åºä¸
int r = fcin.read(buffer);
// read() è¿å -1 表示 EOF
if(r==-1){
break;
}
//åæ¢è¯»å
buffer.flip();
//æç¼å²åºçå
容åå
¥è¾åºæä»¶ä¸
fcout.write(buffer);
//æ¸
空ç¼å²åº
buffer.clear();
}
}
}
```
### SocketChannelåServerSocketChannelç使ç¨
SocketChannelç¨äºå建åºäºTCPåè®®ç客æ·ç«¯å¯¹è±¡ï¼å 为SocketChannelä¸ä¸åå¨accept()æ¹æ³ï¼
æä»¥ï¼å®ä¸è½æä¸ºä¸ä¸ªæå¡ç«¯ç¨åºã
éè¿**connect()æ¹æ³**ï¼SocketChannel对象å¯ä»¥è¿æ¥å°å
¶ä»TCPæå¡å¨ç¨åºã
ServerSocketChannelå
许æä»¬çå¬TCPå议请æ±ï¼éè¿ServerSocketChannelç**accept()**æ¹æ³å建ä¸ä¸ªSocketChannelå¯¹è±¡ç¨æ·ä»å®¢æ·ç«¯è¯»/åæ°æ®ã
- æå¡ç«¯:
1. éè¿ServerSocketChannel ç»å®ipå°åå端å£å·
2. éè¿ServerSocketChannelçaccept()æ¹æ³å建ä¸ä¸ªSocketChannelå¯¹è±¡ç¨æ·ä»å®¢æ·ç«¯è¯»/åæ°æ®
3. åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»å客æ·ç«¯æ°æ®æå客æ·ç«¯åéæ°æ®
4. å
³éSocketChannelåServerSocketChannel
```java
public class Server {
public static void main(String[] args) throws IOException {
//éè¿ServerSocketChannel çopen()æ¹æ³å建ä¸ä¸ªServerSocketChannel对象
ServerSocketChannel ssc=ServerSocketChannel.open();
//1. éè¿ServerSocketChannel ç»å®ipå°åå端å£å·
ssc.socket().bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888));
//2. éè¿ServerSocketChannelçaccept()æ¹æ³å建ä¸ä¸ªSocketChannelå¯¹è±¡ç¨æ·ä»å®¢æ·ç«¯è¯»/åæ°æ®
SocketChannel sc=ssc.accept();
//3. åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»å客æ·ç«¯æ°æ®æå客æ·ç«¯åéæ°æ®
//读å客æ·ç«¯åéçæ°æ®
ByteBuffer buffer=ByteBuffer.allocate(1024);
//ä»ééä¸è¯»åæ°æ®å°ç¼å²åº
sc.read(buffer);
StringBuffer sb=new StringBuffer();
buffer.flip();
while(buffer.hasRemaining()){
sb.append((char)buffer.get());
}
System.out.println(sb.toString());
ByteBuffer buffer2=ByteBuffer.allocate(1024);
//å客æ·ç«¯åéæ°æ®
buffer2.put("data has been received.".getBytes());
buffer2.flip();
sc.write(buffer2);
//4. å
³éSocketChannelåServerSocketChannel
sc.close();
ssc.close();
}
}
```
- 客æ·ç«¯ï¼
1.éè¿SocketChannelè¿æ¥å°è¿ç¨æå¡å¨
2.åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»åæå¡ç«¯æ°æ®æåæå¡ç«¯åéæ°æ®
3.å
³éSocketChannel
```java
public class Client {
public static void main(String[] args) throws IOException {
//1.éè¿SocketChannelè¿æ¥å°è¿ç¨æå¡å¨
SocketChannel sc=SocketChannel.open();
sc.connect(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888));
//2.åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»åæå¡ç«¯æ°æ®æåæå¡ç«¯åéæ°æ®
//åééä¸åå
¥æ°æ®
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.put("hello".getBytes());
buffer.flip();
sc.write(buffer);
//读åä»å®¢æ·ç«¯ä¸è·åçæ°æ®
ByteBuffer buffer2=ByteBuffer.allocate(1024);
sc.read(buffer2);
StringBuffer sb=new StringBuffer();
buffer2.flip();
while(buffer2.hasRemaining()){
sb.append((char)buffer2.get());
}
System.out.println(sb.toString());
//3.å
³éSocketChannel
sc.close();
}
}
```
### DatagramChannelç使ç¨
DataGramChannelï¼ç±»ä¼¼äºjava ç½ç»ç¼ç¨çDatagramSocketç±»ï¼
**使ç¨UDPè¿è¡ç½ç»ä¼ è¾**ï¼ UDPæ¯æ è¿æ¥ï¼é¢åæ°æ®æ¥ææ®µçåè®®ã
- æå¡ç«¯ï¼
```java
public class Server {
public static void main(String[] args) throws IOException {
DatagramChannel dc= DatagramChannel.open();
dc.bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888));
//åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»å客æ·ç«¯æ°æ®æå客æ·ç«¯åéæ°æ®
//读å客æ·ç«¯åéçæ°æ®
ByteBuffer buffer=ByteBuffer.allocate(1024);
//ä»ééä¸è¯»åæ°æ®å°ç¼å²åº
dc.receive(buffer);
StringBuffer sb=new StringBuffer();
buffer.flip();
while(buffer.hasRemaining()){
sb.append((char)buffer.get());
}
System.out.println(sb.toString());
ByteBuffer buffer2=ByteBuffer.allocate(1024);
//å客æ·ç«¯åéæ°æ®
buffer2.put("data has been received.".getBytes());
buffer2.flip();
dc.send(buffer2,new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),9999));
dc.close();
}
}
```
- 客æ·ç«¯ï¼
```java
public class Client {
public static void main(String[] args) throws IOException {
DatagramChannel dc= DatagramChannel.open();
dc.bind(new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),9999));
//åå»ºè¯»æ°æ®/åæ°æ®ç¼å²åºå¯¹è±¡æ¥è¯»åæå¡ç«¯æ°æ®æåæå¡ç«¯åéæ°æ®
//åééä¸åå
¥æ°æ®
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.put("hello".getBytes());
buffer.flip();
dc.send(buffer,new InetSocketAddress(InetAddress.getByName("LAPTOP-D9966H06"),8888));
//读åä»å®¢æ·ç«¯ä¸è·åçæ°æ®
ByteBuffer buffer2=ByteBuffer.allocate(1024);
dc.receive(buffer2);
StringBuffer sb=new StringBuffer();
buffer2.flip();
while(buffer2.hasRemaining()){
sb.append((char)buffer2.get());
}
System.out.println(sb.toString());
dc.close();
}
}
```
### ééä¹é´çæ°æ®ä¼ è¾
å¨Java NIOä¸å¦æä¸ä¸ªchannelæ¯FileChannelç±»åçï¼é£ä¹ä»å¯ä»¥ç´æ¥ææ°æ®ä¼ è¾å°å¦ä¸ä¸ªchannelã
```java
transferFrom() :transferFromæ¹æ³ææ°æ®ä»ééæºä¼ è¾å°FileChannel
transferTo() :transferToæ¹æ³æFileChannelæ°æ®ä¼ è¾å°å¦ä¸ä¸ªFileChhannel
```
```java
public static void copyFile6(String srcFile,String destFile) throws IOException {
FileInputStream fis = new FileInputStream(srcFile);
//è·åè¾å
¥åèæµçæä»¶éé
FileChannel fcin = fis.getChannel();
FileOutputStream fos = new FileOutputStream(destFile);
//è·åè¾åºåèæµçæä»¶éé
FileChannel fcout = fos.getChannel();
//fcinééä¸è¯»åºcount bytes ï¼å¹¶åå
¥fcoutééä¸
//fcin.transferTo(0,fcin.size(),fcout);
//æè
fcout.transferFrom(fcin,0,fcin.size());
}
```
## éæ©å¨
NIO 常常被å«åéé»å¡ IOï¼ä¸»è¦æ¯å 为 NIO å¨ç½ç»éä¿¡ä¸çéé»å¡ç¹æ§è¢«å¹¿æ³ä½¿ç¨ã
NIO å®ç°äº IO å¤è·¯å¤ç¨ä¸ç **Reactor 模å**ï¼ä¸ä¸ªçº¿ç¨ Thread 使ç¨ä¸ä¸ªéæ©å¨ Selector éè¿**è½®è¯¢çæ¹å¼**
å»çå¬å¤ä¸ªéé Channel ä¸çäºä»¶ï¼ä»è让ä¸ä¸ªçº¿ç¨å°±å¯ä»¥å¤çå¤ä¸ªäºä»¶ã
éè¿é
ç½®çå¬çéé Channel 为**éé»å¡**ï¼é£ä¹å½ Channel ä¸ç IO äºä»¶è¿æªå°è¾¾æ¶ï¼
å°±ä¸ä¼è¿å
¥é»å¡ç¶æä¸ç´çå¾
ï¼èæ¯ç»§ç»è½®è¯¢å
¶å® Channelï¼æ¾å° IO äºä»¶å·²ç»å°è¾¾ç Channel æ§è¡ã
å 为å建ååæ¢çº¿ç¨çå¼éå¾å¤§ï¼å æ¤ä½¿ç¨ä¸ä¸ªçº¿ç¨æ¥å¤çå¤ä¸ªäºä»¶è䏿¯ä¸ä¸ªçº¿ç¨å¤çä¸ä¸ªäºä»¶ï¼
å¯¹äº IO å¯éåçåºç¨å
·æå¾å¥½å°æ§è½ã
åºè¯¥æ³¨æçæ¯ï¼åªæå¥æ¥å Channel æè½é
置为éé»å¡ï¼è FileChannel ä¸è½ï¼
为 FileChannel é
ç½®éé»å¡ä¹æ²¡ææä¹ã
使ç¨Selectorçä¼ç¹ï¼
ä½¿ç¨æ´å°ççº¿ç¨æ¥å°±å¯ä»¥æ¥å¤çééäºï¼ ç¸æ¯ä½¿ç¨å¤ä¸ªçº¿ç¨ï¼
é¿å
äºçº¿ç¨ä¸ä¸æåæ¢å¸¦æ¥çå¼éã
### 1. åå»ºéæ©å¨
```java
Selector selector = Selector.open();
```
### 2. å°ééæ³¨åå°éæ©å¨ä¸
```java
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);//ééå¿
é¡»é
置为éé»å¡æ¨¡å¼
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
```
ééå¿
é¡»é
置为éé»å¡æ¨¡å¼ï¼å¦å使ç¨éæ©å¨å°±æ²¡æä»»ä½æä¹äºï¼å ä¸ºå¦æééå¨æä¸ªäºä»¶ä¸è¢«é»å¡ï¼é£ä¹æå¡å¨å°±ä¸è½ååºå
¶å®äºä»¶ï¼å¿
é¡»çå¾
è¿ä¸ªäºä»¶å¤ç宿¯æè½å»å¤çå
¶å®äºä»¶ï¼æ¾ç¶è¿åéæ©å¨çä½ç¨èéèé©°ã
å¨å°ééæ³¨åå°éæ©å¨ä¸æ¶ï¼è¿éè¦æå®è¦æ³¨åçå
·ä½äºä»¶ï¼ä¸»è¦æä»¥ä¸å ç±»ï¼
- SelectionKey.OP_CONNECT
- SelectionKey.OP_ACCEPT
- SelectionKey.OP_READ
- SelectionKey.OP_WRITE
å®ä»¬å¨ SelectionKey çå®ä¹å¦ä¸ï¼
```java
public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;
```
å¯ä»¥çåºæ¯ä¸ªäºä»¶å¯ä»¥è¢«å½æä¸ä¸ªä½åï¼ä»èç»æäºä»¶éæ´æ°ãä¾å¦ï¼
```java
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
```
### 3. çå¬äºä»¶
```java
int num = selector.select();
```
ä½¿ç¨ select() æ¥çå¬å°è¾¾çäºä»¶ï¼å®ä¼**ä¸ç´é»å¡ç´å°æè³å°ä¸ä¸ªäºä»¶å°è¾¾**ã
### 4. è·åå°è¾¾çäºä»¶
```java
Set keys = selector.selectedKeys();
Iterator keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// ...
} else if (key.isReadable()) {
// ...
}
keyIterator.remove();
}
```
### 5. äºä»¶å¾ªç¯
å ä¸ºä¸æ¬¡ select() è°ç¨ä¸è½å¤ç宿æçäºä»¶ï¼å¹¶ä¸æå¡å¨ç«¯æå¯è½éè¦ä¸ç´çå¬äºä»¶ï¼å æ¤æå¡å¨ç«¯å¤çäºä»¶ç代ç ä¸è¬ä¼æ¾å¨ä¸ä¸ªæ»å¾ªç¯å
ã
```java
while (true) {
int num = selector.select();
Set keys = selector.selectedKeys();
Iterator keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// ...
} else if (key.isReadable()) {
// ...
}
keyIterator.remove();
}
}
```
## Reactor 模å
æä»¬ç¥éï¼å¨æä»¬ä½¿ç¨ä¼ ç»æ¹æ³è¿è¡ç½ç»IOæä½çæ¶åï¼éè¦ä½¿ç¨ä¸ä¸ªçº¿ç¨çå¬IOäºä»¶ï¼å½äºä»¶å°è¾¾ä¹åï¼å建ä¸ä¸ªçº¿ç¨å»å¤çæ¥æ¶å°çIOäºä»¶ï¼è¿ç§æ¨¡åéè¦å建大éç线ç¨ï¼ä¼æå¤§ç浪费å
åçèµæºã
è¿ç§æ
åµä¸ï¼æäººæåºäºReactor模å¼ï¼å¨Reactorä¸ï¼æå为ä¸åçå°çº¿ç¨æè
åè¿ç¨ï¼è¿äºè¢«æåçå°çº¿ç¨ååè¿ç¨å¯¹åºçæ¯handlerï¼æ¯ä¸ç§handleré½ä¼å¤çä¸ç§äºä»¶ï¼eventï¼ãè¿ä¸ªéè¦ä¸ä¸ªå
¨å±ç管çè
selectorï¼åchannel注åæå
´è¶£çäºä»¶ï¼selector䏿å¨channelä¸çæµæ¯å¦æè¯¥äºä»¶åçï¼å¦ææ²¡æï¼é£ä¹ä¸»çº¿ç¨ä¼è¢«é»å¡ï¼å¦åä¼è°ç¨ç¸åºçäºä»¶å¤ç彿°æ¥å¤çãè¿äºäºä»¶å
¸åçæè¿æ¥ã读åãåå
¥ï¼æä»¬éè¦ä¸ºè¿äºäºä»¶å嫿ä¾å¤çå¨ï¼äºä»¶å°è¾¾åååå°å¤çå¨ä¸å°±å¯ä»¥è¿åå¤çåé¢çäºä»¶ï¼ååéè½å¤æå¤§çæé«ãå
¶ä¸å®ä¹äºä»¥ä¸ä¸ç§è§è²ï¼
- Reactorï¼è´è´£å°IOäºä»¶åæ´¾ç»æå®çå¤çå¨ï¼Handlerï¼
- Acceptorï¼è´è´£å¤çæ°çè¿æ¥ï¼å¹¶å°è¯·æ±ç§»äº¤ç»Reactor
- Handlerï¼è´è´£è¯»åçå¤çå¨
### åReactoråçº¿ç¨æ¨¡å
è¿æ¯æåºæ¬çåReactoråçº¿ç¨æ¨¡åãå
¶ä¸Reactor线ç¨ï¼è´è´£å¤è·¯å¤ç¨socketï¼ææ°è¿æ¥å°æ¥è§¦åäºä»¶ä¹åï¼äº¤ç±Acceptorè¿è¡å¤çï¼æIO读åäºä»¶ä¹å交ç»hanlder å¤çã
Acceptor主è¦ä»»å¡å°±æ¯æå»ºhandler ï¼å¨è·åå°åclientç¸å
³çSocketChannelä¹å ï¼ç»å®å°ç¸åºçhanlderä¸ï¼å¯¹åºçSocketChannelæè¯»åäºä»¶ä¹åï¼åºäºreactor åå,hanlderå°±å¯ä»¥å¤çäºï¼ææçIOäºä»¶é½ç»å®å°selectorä¸ï¼æReactorååï¼ã
该模å éç¨äºå¤çå¨é¾ä¸ä¸å¡å¤çç»ä»¶è½å¿«é宿çåºæ¯ãä¸è¿ï¼è¿ç§åçº¿ç¨æ¨¡åä¸è½å
åå©ç¨å¤æ ¸èµæºï¼æä»¥å®é
使ç¨çä¸å¤ã
### åReactorå¤çº¿ç¨æ¨¡å
ç¸å¯¹äºç¬¬ä¸ç§å线ç¨çæ¨¡å¼æ¥è¯´ï¼å¨å¤çä¸å¡é»è¾ï¼ä¹å°±æ¯è·åå°IOç读åäºä»¶ä¹åï¼äº¤ç±**çº¿ç¨æ± **æ¥å¤çï¼è¿æ ·å¯ä»¥åå°ä¸»reactorçæ§è½å¼éï¼ä»èæ´ä¸æ³¨çåäºä»¶ååå·¥ä½äºï¼ä»èæåæ´ä¸ªåºç¨çååéã
### å¤Reactorå¤çº¿ç¨æ¨¡å
第ä¸ç§æ¨¡åæ¯èµ·ç¬¬äºç§æ¨¡åï¼æ¯å°Reactoråæä¸¤é¨åï¼
- mainReactorï¼è´è´£çå¬server socketï¼ç¨æ¥**å¤çæ°è¿æ¥ç建ç«**ï¼å°å»ºç«çsocketChannelæå®æ³¨åç»subReactorï¼
- subReactorï¼ç»´æ¤èªå·±çselector, acceptä¼å°è¿æ¥äº¤ç»å®æ¥å¤çï¼è¯»åï¼readãsendï¼ç½ç»æ°æ®ï¼å¯¹äºä¸å¡é»è¾çå¤çï¼å°å
¶æç»çº¿ç¨æ± ä¸çworkeræ¥å¤çã
å¨è¯¥æ¨¡åä¸ï¼mainReactor ä¸»è¦æ¯ç¨æ¥å¤çç½ç»IO è¿æ¥å»ºç«æä½ï¼é常ä¸ä¸ªçº¿ç¨å°±å¯ä»¥å¤çï¼èsubReactor主è¦åå建ç«èµ·æ¥çsocketåæ°æ®äº¤äºåäºä»¶ä¸å¡å¤çæä½ï¼å®ç个æ°ä¸ä¸è¬æ¯åCPU个æ°çåï¼ä¸ä¸ªsubReactor对åºä¸ä¸ªçº¿ç¨å¤çã
æ¤ç§æ¨¡åä¸ï¼æ¯ä¸ªæ¨¡åç工使´å ä¸ä¸ï¼è¦å度æ´ä½ï¼æ§è½åç¨³å®æ§ä¹å¤§éçæåï¼æ¯æçå¯å¹¶å客æ·ç«¯æ°éå¯è¾¾å°ä¸ç¾ä¸çº§å«ãå
³äºæ¤ç§æ¨¡åçåºç¨ï¼ç®åæå¾å¤ä¼ç§çæ¡æ¶å·²ç»åºç¨ï¼æ¯å¦Nettyã
### ä¼ç¼ºç¹
**ä¼ç¹ï¼**
1. ååºå¿«ï¼ä¸å¿
为åä¸ªåæ¥æ¶é´æé»å¡ï¼è½ç¶Reactoræ¬èº«ä¾ç¶æ¯åæ¥ç
2. ç¼ç¨ç¸å¯¹ç®åï¼å¯ä»¥æå¤§ç¨åº¦çé¿å
夿çå¤çº¿ç¨å忥é®é¢ï¼å¹¶ä¸é¿å
äºå¤çº¿ç¨/è¿ç¨ç忢å¼é
3. 坿©å±æ§ï¼å¯ä»¥æ¹ä¾¿çéè¿å¢å Reactorå®ä¾ä¸ªæ°æ¥å
åå©ç¨CPUèµæº
4. å¯å¤ç¨æ§ï¼reactoræ¡æ¶æ¬èº«ä¸å
·ä½äºä»¶å¤çé»è¾æ å
³ï¼å
·æå¾é«çå¤ç¨æ§
**缺ç¹ï¼**
1. ç¸æ¯ä¼ ç»çç®å模åï¼Reactorå¢å äºä¸å®ç夿æ§ï¼å èæä¸å®ç鍿§ï¼å¹¶ä¸ä¸æäºè°è¯
2. Reactor模å¼éè¦åºå±çSynchronous Event Demultiplexeræ¯æï¼æ¯å¦Javaä¸çSelectoræ¯æï¼æä½ç³»ç»çselectç³»ç»è°ç¨æ¯æï¼å¦æè¦èªå·±å®ç°Synchronous Event Demultiplexerå¯è½ä¸ä¼æé£ä¹é«æ
3. Reactor模å¼å¨IOè¯»åæ°æ®æ¶è¿æ¯å¨åä¸ä¸ªçº¿ç¨ä¸å®ç°çï¼å³ä½¿ä½¿ç¨å¤ä¸ªReactoræºå¶çæ
åµä¸ï¼é£äºå
±äº«ä¸ä¸ªReactorçChannel妿åºç°ä¸ä¸ªé¿æ¶é´çæ°æ®è¯»åï¼ä¼å½±åè¿ä¸ªReactorä¸å
¶ä»Channelçç¸åºæ¶é´ï¼æ¯å¦å¨å¤§æä»¶ä¼ è¾æ¶ï¼IOæä½å°±ä¼å½±åå
¶ä»Clientçç¸åºæ¶é´ï¼å è对è¿ç§æä½ï¼ä½¿ç¨ä¼ ç»çThread-Per-Connectionæè®¸æ¯ä¸ä¸ªæ´å¥½çéæ©ï¼æåæ¤æ¶ä½¿ç¨Proactor模å¼
## 奿¥å NIO å®ä¾
```java
public class NIOServer {
public static void main(String[] args) throws IOException {
//1. åå»ºéæ©å¨
Selector selector = Selector.open();
//2.å°ééæ³¨åå°éæ©å¨ä¸
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
//ééå¿
é¡»é
置为éé»å¡æ¨¡å¼ï¼å¦å使ç¨éæ©å¨å°±æ²¡æä»»ä½æä¹äº
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
ServerSocket ss=ssChannel.socket();
ss.bind(new InetSocketAddress("127.0.0.1",8888));
while (true){
//3. çå¬äºä»¶
selector.select();
//4. è·åå°è¾¾çäºä»¶
Set keys = selector.selectedKeys();
Iterator keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();
// æå¡å¨ä¼ä¸ºæ¯ä¸ªæ°è¿æ¥å建ä¸ä¸ª SocketChannel
SocketChannel sChannel = ssChannel1.accept();
sChannel.configureBlocking(false);
// è¿ä¸ªæ°è¿æ¥ä¸»è¦ç¨äºä»å®¢æ·ç«¯è¯»åæ°æ®
sChannel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel sChannel = (SocketChannel) key.channel();
System.out.println(readDataFromSocketChannel(sChannel));
sChannel.close();
}
keyIterator.remove();
}
}
}
private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024);
StringBuilder data = new StringBuilder();
while (true) {
buffer.clear();
int r = sChannel.read(buffer);
if (r == -1) {
break;
}
buffer.flip();
int limit = buffer.limit();
char[] dst = new char[limit];
for (int i = 0; i < limit; i++) {
dst[i] = (char) buffer.get(i);
}
data.append(dst);
buffer.clear();
}
return data.toString();
}
}
```
```java
public class NIOClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8888);
OutputStream out = socket.getOutputStream();
String s = "hello world";
out.write(s.getBytes());
out.close();
}
}
```
## å
åæ å°æä»¶
å
åæ å°æä»¶ I/O æ¯ä¸ç§è¯»ååæä»¶æ°æ®çæ¹æ³ï¼å®å¯ä»¥æ¯å¸¸è§çåºäºæµæè
åºäºééç I/O å¿«å¾å¤ã
åå
åæ å°æä»¶åå
¥å¯è½æ¯å±é©çï¼åªæ¯æ¹åæ°ç»çå个å
ç´ è¿æ ·çç®åæä½ï¼å°±å¯è½ä¼ç´æ¥ä¿®æ¹ç£çä¸çæä»¶ãä¿®æ¹æ°æ®ä¸å°æ°æ®ä¿åå°ç£çæ¯æ²¡æåå¼çã
ä¸é¢ä»£ç è¡å°æä»¶çå 1024 个åèæ å°å°å
åä¸ï¼map() æ¹æ³è¿åä¸ä¸ª MappedByteBufferï¼å®æ¯ ByteBuffer çåç±»ãå æ¤ï¼å¯ä»¥å使ç¨å
¶ä»ä»»ä½ ByteBuffer 䏿 ·ä½¿ç¨æ°æ å°çç¼å²åºï¼æä½ç³»ç»ä¼å¨éè¦æ¶è´è´£æ§è¡æ å°ã
```java
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);
```
## NIOä¸IO对æ¯
NIO 䏿®é I/O çåºå«ä¸»è¦æä»¥ä¸ä¸ç¹ï¼
- NIO æ¯éé»å¡çï¼
- NIO é¢ååï¼I/O é¢åæµã
- NIOæéæ©å¨ï¼èI/O没æã
## Path
Java7䏿件IOåçäºå¾å¤§çååï¼ä¸é¨å¼å
¥äºå¾å¤æ°çç±»æ¥å代忥ç
åºäºjava.io.Fileçæä»¶IOæä½æ¹å¼ã
### å建ä¸ä¸ªPath
使ç¨Pathså·¥å
·ç±»çget()æ¹æ³å建Path对象
```java
public class PathDemo {
public static void main(String[] args) {
//æ¹å¼ä¸
Path path=Paths.get("demo5.txt");
System.out.println(path);
//æ¹å¼äº
Path path2 = FileSystems.getDefault().getPath("demo5.txt");
System.out.println(path2);
}
}
```
### FileåPathä¹é´ç转æ¢ï¼FileåURIä¹é´ç转æ¢
```java
public class PathDemo2 {
public static void main(String[] args) {
Path path=Paths.get("demo5.txt");
File file=path.toFile();
URI uri=path.toUri();
System.out.println(path);
System.out.println(file);
System.out.println(uri);
}
}
```
```html
demo5.txt
demo5.txt
file:///F:/Java_Review/05Java/JavaIO/demo5.txt
```
### è·åPathçç¸å
³ä¿¡æ¯
```java
public class PathDemo3 {
public static void main(String[] args) {
Path path= Paths.get("demo3\\test3.txt");
System.out.println("æä»¶åï¼"+ path.getFileName());
System.out.println("åç§°å
ç´ çæ°éï¼"+path.getNameCount());
System.out.println("ç¶è·¯å¾ï¼"+ path.getParent());
System.out.println("æ ¹è·¯å¾ï¼"+ path.getRoot());
System.out.println("æ¯å¦æ¯ç»å¯¹è·¯å¾:"+path.isAbsolute());
//startWith() åæ°æ¢å¯ä»¥æ¯å符串ï¼ä¹å¯ä»¥æ¯Path
System.out.println("æ¯å¦æ¯ä»¥è·¯å¾demo3å¼å¤´ï¼"+path.startsWith(Paths.get("demo3")));
System.out.println("该路å¾çå符串形å¼ï¼"+path.toString());
}
}
```
```html
æä»¶åï¼test3.txt
åç§°å
ç´ çæ°éï¼2
ç¶è·¯å¾ï¼demo3
æ ¹è·¯å¾ï¼null
æ¯å¦æ¯ç»å¯¹è·¯å¾:false
æ¯å¦æ¯ä»¥è·¯å¾demo3å¼å¤´ï¼true
该路å¾çå符串形å¼ï¼demo3\test3.txt
```
### ç§»é¤Pathä¸çåä½é¡¹
\\ .è¡¨ç¤ºçæ¯å½åç®å½
â
\\ ..表示ç¶ç®å½æè
说æ¯ä¸ä¸çº§ç®å½
normalize() : è¿åä¸ä¸ªè·¯å¾ï¼è¯¥è·¯å¾æ¯ååºåä½é¡¹çè·¯å¾ã
toRealPath() : å¯ä»¥çæï¼å
è¿è¡toAbsolutePath()æä½ï¼ç¶åè¿è¡normalize()æä½
```java
public class PathDemo4 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("./demo3");
System.out.println("original ï¼"+ path.toAbsolutePath());
System.out.println("after normalize:"+ path.toAbsolutePath().normalize());
System.out.println("after toRealPath:"+ path.toRealPath());
}
}
```
```html
original ï¼F:\Java_Review\05Java\JavaIO\.\demo3
after normalize:F:\Java_Review\05Java\JavaIO\demo3
after toRealPath:F:\Java_Review\05Java\JavaIO\demo3
```
```java
public class PathDemo5 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("../JavaIO");
System.out.println("original ï¼"+ path.toAbsolutePath());
System.out.println("after normalize:"+ path.toAbsolutePath().normalize());
System.out.println("after toRealPath:"+ path.toRealPath());
}
}
```
```html
original ï¼F:\Java_Review\05Java\JavaIO\..\JavaIO
after normalize:F:\Java_Review\05Java\JavaIO
after toRealPath:F:\Java_Review\05Java\JavaIO
```
## Files
java.nio.file.Filesç±»æ¯åjava.nio.file.Pathç¸ç»å使ç¨ç
### æ£æ¥ç»å®çPathå¨æä»¶ç³»ç»ä¸æ¯å¦åå¨
Files.exists()ï¼æ£æµæä»¶è·¯å¾æ¯å¦åå¨
```java
public class FilesDemo {
public static void main(String[] args) {
Path path = Paths.get("demo5.txt");
//LinkOptions.NOFOLLOW_LINKS:è¡¨ç¤ºæ£æµæ¶ä¸å
å«ç¬¦å·é¾æ¥æä»¶ã
boolean isExist= Files.exists(path,new LinkOption[]{LinkOption.NOFOLLOW_LINKS});
System.out.println(isExist);
}
}
```
### å建æä»¶/æä»¶å¤¹
Files.createFile()ï¼å建æä»¶
Files.createDirectory()ï¼ å建æä»¶å¤¹
Files.createDirectories()ï¼ å建æä»¶å¤¹
```java
public class FilesDemo2 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("demo7.txt");
if(!Files.exists(path)){
Files.createFile(path);
}
Path path2=Paths.get("demo4");
if(!Files.exists(path2)){
Files.createDirectory(path2);
}
Path path3=Paths.get("demo5\\test");
if(!Files.exists(path3)){
Files.createDirectories(path3);
}
}
}
```
### å 餿件æç®å½
Files.delete()ï¼å é¤ä¸ä¸ªæä»¶æç®å½
```java
public class FilesDemo3 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("demo7.txt");
Files.delete(path);
}
}
```
### æä¸ä¸ªæä»¶ä»ä¸ä¸ªå°åå¤å¶å°å¦ä¸ä¸ªä½ç½®
Files.copy()ï¼æä¸ä¸ªæä»¶ä»ä¸ä¸ªå°åå¤å¶å°å¦ä¸ä¸ªä½ç½®
```java
public class FilesDemo4 {
public static void main(String[] args) throws IOException {
Path srcPath= Paths.get("demo6.txt");
Path destPath=Paths.get("demo7.txt");
//Files.copy(srcPath,destPath);
//强å¶è¦çå·²ç»åå¨çç®æ æä»¶
Files.copy(srcPath,destPath, StandardCopyOption.REPLACE_EXISTING);
}
}
```
### è·åæä»¶å±æ§
```java
public class FilesDemo5 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("demo7.txt");
System.out.println(Files.getLastModifiedTime(path));
System.out.println(Files.size(path));
System.out.println(Files.isSymbolicLink(path));
System.out.println(Files.isDirectory(path));
System.out.println(Files.readAttributes(path,"*"));
}
}
```
### éåä¸ä¸ªæä»¶å¤¹
```java
public class FilesDemo6 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("demo3\\demo2");
DirectoryStream paths=Files.newDirectoryStream(path);
for(Path p:paths){
System.out.println(p.getFileName());
}
}
}
```
### éåæ´ä¸ªæä»¶ç®å½
FileVisitoréè¦è°ç¨æ¹èªè¡å®ç°ï¼ç¶åä½ä¸ºåæ°ä¼ å
¥walkFileTree()ï¼
FileVisitorçæ¯ä¸ªæ¹æ³ä¼å¨éåè¿ç¨ä¸è¢«è°ç¨å¤æ¬¡ã
```java
public class FilesDemo7 {
public static void main(String[] args) throws IOException {
Path path= Paths.get("demo3\\demo2");
List paths=new ArrayList<>();
Files.walkFileTree(path,new FileVisitor(paths));
System.out.println("paths:"+paths);
}
private static class FileVisitor extends SimpleFileVisitor {
private List paths;
public FileVisitor(List paths){
this.paths=paths;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if(file.toString().endsWith(".txt")){
paths.add(file.getFileName());
}
return super.visitFile(file, attrs);
}
}
}
```
è¾åºç»æï¼
```html
paths:[a.txt, test2.txt, test.txt, test3.txt]
```
# åèèµæ
- https://juejin.im/post/5b4570cce51d451984695a9b