JAVA NIO 之1
第一次接觸,所以先從定義開始吧
java.nio 全程是java non-blocking IO,非阻塞型IO。根據這個段時間的學習,知道,java.IO是同步阻塞型的,每一次呼叫writer和read的時候,都會加鎖,意味如果很多使用者的話,必須排隊
NIO主要有三大核心部分:Channel,Buffer,Selector。傳統IO基於位元組流和字元流進行操作,而NIO基於Channel(通道)和Buffer(緩衝區)進行操作。資料總是由通道讀取到緩衝區,或者從緩衝區寫入到通道。Selector(選擇區)用於監聽多個通道的事件(比如:連線開啟,資料到達)。因此單執行緒可以監聽多個數據通道。
NIO和傳統IO的第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。
IO的各種流是阻塞的。這意味著,當一個執行緒呼叫read或write時,該執行緒被阻塞,直到有一些 資料被讀取,或資料完全寫入。該執行緒在此期間不能幹任何事情。NIO是非阻塞模式,使一個執行緒從某通道傳送請求讀取資料,但它只能得到目前可用的資料。如果目前沒有資料可用時,就什麼也不會獲取。而不是保持執行緒阻塞,所以直到資料變的可讀取之前,該執行緒可以繼續做其他的事情,非阻塞的寫也是如此。執行緒通常將非阻塞IO空閒時間用在其他通道上執行IO操作,所以一個單獨的執行緒在現在可以管理多個輸入和輸出通道(channel)。
channel,不像流,流是單向的,channel是雙向的,既可以用來讀,也可以用來寫。
//通道表示一個實體的(硬體裝置,檔案,網路套接字,一個程式元件)的開放性連線,執行一個多或多個IO操作。讀或寫。。。 //通道要麼開啟,要麼關閉,通道在建立的時候開啟,關閉的時候關閉。 //一旦關閉。任何關於IO的操作都會拋異常 //多執行緒訪問安全 public interface Channel extends Closeable{ //判斷通道是否開啟 public boolean isOpen(); //關閉通道 public void close() throws IOException; }
buffer,buffer用於和channel進行互動,資料是從通道進入緩衝區,從緩衝區寫入到通道中的 。
實際上是一個容器,連續陣列,Channel提供從檔案、網路讀取資料的渠道,但是讀寫的資料都必須經過Buffer
一個buffer的capacity是buffer包含元素的數量,buffer的capacity是不為負且不會改變
buffer的limit是第一個不被讀或寫的元素的指標,buffer的limit不為負且不能超過buffer的capacity
buffer的position是下一個將要被讀或寫的元素的指標,buffer的position不為負且不能超過buffer的limit
private int mark = -1; //用於記錄當前position的前一個位置或者預設是-1
private int position = 0;
private int limit;
private int capacity;
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
this.mark = mark;
}
}
public final Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
if (position > limit) position = limit;
if (mark > limit) mark = -1;
return this;
}
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
if (mark > position) mark = -1;
return this;
}
向Buffer中寫的資料
從Channel中寫入。。。
selector:selector執行單執行緒處理多個Channel。
關於FileChannel
// 是一個讀取,寫入,對映,和操作檔案的通道
// java.io.FileInputStream#getChannel()
// java.io.FileOutputStream#getChannel()
// java.io.RandomAccessFile#getChannel()
public abstract class FileChannel
extends AbstractInterruptibleChannel
implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
//初始化一個新的例項
protected FileChannel() { }
//開啟或建立一個檔案,返回訪問檔案的通道
//path 檔案的路徑
//options 檔案開啟的方式
//attrs 可選的檔案屬性列表
public static FileChannel open(Path path,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
FileSystemProvider provider = path.getFileSystem().provider();
return provider.newFileChannel(path, options, attrs);
}
//從通道中讀取一個位元組序列到ByteBuffer中
/每寫讀次,ByteBuffer 中的positon都會更新,大小為positon + n
//其中 n = ByteBuffer.limit,若最後一次,就是最後一次讀取的byte的數目
public abstract int read(ByteBuffer dst) throws IOException;
//從通道中讀取位元組序列到指定的ByteBuffer陣列
public abstract long read(ByteBuffer[] dsts, int offset, int length)
throws IOException;
public final long read(ByteBuffer[] dsts) throws IOException {
return read(dsts, 0, dsts.length);
}
//Bytes 從該通道的當前檔案位置開始讀取位元組,然後使用實際讀取的位元組數更新檔案位置。
//從給定的buffer中,向通道中寫一序列位元組
//每寫一次,ByteBuffer 中的positon都會更新,大小為positon + n
//其中 n = ByteBuffer.limit,若最後一次,就是最後一次讀取的byte的數目
public abstract int write(ByteBuffer src) throws IOException;
//從給定的buffer[]中,從offset開始,讀取length位元組,向通道中寫入
public abstract long write(ByteBuffer[] srcs, int offset, int length)
throws IOException;
public final long write(ByteBuffer[] srcs) throws IOException {
return write(srcs, 0, srcs.length);
}
//返回通道中檔案的位置
public abstract long position() throws IOException;
//設定通道中檔案的位置
public abstract FileChannel position(long newPosition) throws IOException;
//返回當前通道中檔案的大小(實時)
public abstract long size() throws IOException;
//將此通道的檔案擷取為指定大小
public abstract FileChannel truncate(long size) throws IOException;
//將位元組從此通道的檔案傳輸到給定的可寫位元組通道。
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;
。。。。。。。。。。。。。
public class JavaNio {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream("E:\\sourcecode\\hello.txt");
FileChannel inChannel = ((FileInputStream) in).getChannel();
OutputStream out = new FileOutputStream("E:\\sourcecode\\hello1.txt");
FileChannel outChannel = ((FileOutputStream) out).getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(2);
while((inChannel.read(byteBuffer))!=-1){
byteBuffer.flip();
if(byteBuffer.hasRemaining()){
outChannel.write(byteBuffer);
}
byteBuffer.compact();
}
out.close();
in.close();
}
}
//分配一個新的位元組緩衝區。
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) { // package-private
super(-1, 0, lim, cap, new byte[cap], 0);
}
/***************************************************
buf.clear(); // Prepare buffer for use
while (in.read(buf) >= 0 || buf.position != 0) {
buf.flip();
out.write(buf);
buf.compact(); // In case of partial write
}
***************************************************/
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
public final boolean hasRemaining() {
return position < limit;
}