一.Channel
- 通道是用于字節緩沖區和位于通道另一邊的數據實體之間執行傳輸數據。
- NIO主要分為File IO和Steam IO,對應通道分為Filechannel和SocketChannel(Socketchannel、ServerSocketChannel和DatagramChannel)。File IO沒有非阻塞模式。
- 通道可以多種方式創建,SocketChannel提供直接創建Socket通道的工廠方法(SocketChannel.open),FileChannel只能通過一個打開的RandomAccessFile、FileInputSteam或者FileOutputSteam對象調用getChannel方法獲取,不可以直接創建。
- 本文主要討論Filechannel,非阻塞通信在下節總結
二.Filechannel
- 層次圖
- 頂層Channel接口提供了isOpen方法判斷通道是否打開和close方法關閉一個打開的通道,InterruptibleChannel是一個標志接口,當通道使用時可以標志該通道可以被中斷的。WritableByteChannel和ReadableByteChannel表明通道只能字節緩沖區上操作。Scatter和Gather表示可以在多個緩沖區上執行IO操作。
-
FilechannelImlp是其重要子類
image.png
- API
1.map(MapMode mode, long position, long size):可以在一個打開的文件和一個特殊類型的ByteBuffer之間建立一個虛擬內存映射(返回一個MappedByteBuffer對象)。get方法會從磁盤文件中獲取文件當前的數據內容,如果建立映射之后文件被其他進程修改,對該進程也是可見的。put方法會更新磁盤上的文件,對文件的修改對其他進程也是可見的。
2.read/write(ByteBuffer var1):從Buffe讀數據,從源碼中可看出讀寫是鎖了整個線程
public int read(ByteBuffer var1) throws IOException {
Object var2 = this.positionLock;
synchronized(this.positionLock) {
........
var3 = IOUtil.read(this.fd, var1, -1L, this.nd);
........
} finally {
.......
}
}
}
}
三.實例
- read(new FileReader("a.txt")):NIO
readByStream(new File("a.txt")):傳統IO
readByMap(new File("a.txt")):內存映射
package IO;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* Created by admin on 2017/9/21.
*/
public class Stream {
public static void main(String[] args) throws IOException {
read(new FileReader("a.txt"));
readByStream(new File("a.txt"));
readByMap(new File("a.txt"));
new Thread(new Runnable() {
@Override
public void run() {
readByNio(new File("a.txt"), 2);
}
}).start();
}
private static void readByStream(File file) {
BufferedInputStream bs = null;
BufferedOutputStream fs = null;
try {
bs = new BufferedInputStream(new FileInputStream(file));
fs = new BufferedOutputStream(new FileOutputStream(new File("c.txt")));
byte[] b = new byte[1024];
while (bs.read(b) != -1) {
fs.write(b);
fs.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//關閉流,其實關閉的就是java調用的系統底層資源。在關閉前,會先刷新該流。
if (fs != null && fs != null) {
Integer a = 1;
try {
bs.close();
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void read(FileReader file) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(file);
//如果d文件中有數據,true表示繼續往文件中追加數據
bw = new BufferedWriter(new FileWriter("d.txt", false));
String line = null;
//高效字符輸入流的特有方法readline(),每次讀取一行數據
while ((line = br.readLine()) != null) {
bw.write(line);
//高效字符輸出流的特有方法newline()
bw.newLine();
//將緩沖區中的數據刷到目的地文件中
bw.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//關閉流,其實關閉的就是java調用的系統底層資源。在關閉前,會先刷新該流。
if (bw != null && br != null) {
try {
br.close();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void readByNio(File file, Integer type) {
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
FileChannel channel = null;
FileChannel channel1 = null;
String name = "";
if (type == 1) {
name = "b.txt";
} else {
name = "c.txt";
}
try {
fileInputStream = new FileInputStream(file);
fileOutputStream = new FileOutputStream(new File(name));
channel1 = fileOutputStream.getChannel();
channel = fileInputStream.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int read = channel.read(buf);
while (read != -1) {
buf.flip();
while (buf.hasRemaining()) {
channel1.write(buf);
}
buf.compact();
read = channel.read(buf);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (channel1 != null) {
try {
channel1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void readByMap(File file) {
FileChannel a = null;
FileChannel b=null;
try {
a = new RandomAccessFile("a.txt", "rw").getChannel();
b = new RandomAccessFile("e.txt", "rw").getChannel();
MappedByteBuffer in = a.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
MappedByteBuffer out = b.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
out.put(in);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (a!=null){
a.close();
}
if (b!=null){
a.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}