2018-09-09微服務筆記(五)之 NIO
阿新 • • 發佈:2018-11-06
1.IO與NIO區別
NIO | IO |
面向流 | 面向緩衝 |
阻塞IO | 非阻塞 |
無 | 選擇器 |
2.三個屬性
2.1 capacity:Buffer的記憶體固定的一個大小值,一般建立Buffer時初始化寫入
2.2 position在讀和寫情況的分析:
1)寫資料到Buffer中時,position表示寫入資料的當前位置。position的初始值為0.當一個byte、long等資料寫到Buffer後, position會向下移動到下一個可插入資料的Buffer單元
2)讀資料到Buffer中時,position表示讀入資料的當前位置,如position=2時表示已開始讀入了3個byte,或從第3個byte開始讀取。通過ByteBuffer.flip()切換到讀模式時position會被重置為0,當Buffer從position讀入資料後,position會下移到下一個可讀入的資料Buffer單元。
2.3 limit在讀和寫情況的分析:
1)寫資料時,limit表示可對Buffer最多寫入多少個數據。
2)讀資料時,limit表示Buffer裡有多少可讀資料(not null的資料),因此能讀到之前寫入的所有資料
2.4 demo
import java.nio.ByteBuffer; public class Test01 { public static void main(String[] args) { //建立緩衝區,最大為1024,即capacity=1024 ByteBuffer bb = ByteBuffer.allocate(1024); //輸出屬性 System.out.println(bb.limit()); //實際可寫入大小 System.out.println(bb.capacity()); //最大大小 System.out.println(bb.position()); //當前處理位置 //放入資料 System.out.println("------------放入資料"); bb.put("abcd1234".getBytes()); //輸出屬性 System.out.println(bb.limit()); //當寫入的時候表示最多可以寫入的資料量,此時為1024 System.out.println(bb.capacity()); //最大大小 System.out.println(bb.position()); //當前處理位置 //輸出 System.out.println("-------------輸出資料"); bb.flip();//將position位置重置為0,下面會做比較 byte[] b = new byte[bb.limit()]; //通過flip重置position位置後,此時的limit表示緩衝區可讀資料的長度,此時limit=8 bb.get(b); System.out.println(new String(b,0,bb.limit())); //重複讀取緩衝區資料 System.out.println("------------重複讀資料"); bb.rewind();//重置下面會做比較 byte[] b1 = new byte[bb.limit()]; bb.get(b1); System.out.println(new String(b1,0,bb.limit())); //清空緩衝區 System.out.println("--------清空緩衝區"); bb.clear(); System.out.println(bb.limit()); System.out.println(bb.capacity()); System.out.println(bb.position()); System.out.println((char)bb.get());//仍可以讀出資料,應為clear方法只是單純的將三個屬性重置,資料並沒用清除 } }
2.5 clear、flip、rewind 區別
2.5.1 clear原始碼
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
clear方法將position重置為0,將可讀寫範圍limit設定為最大範圍capacity;
2.5.2 flip
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
將可讀寫範圍設定為position的值,這樣在讀操作時,limit的值就是緩衝區中可以讀寫資料的大小。
將position的值重置。
2.5.3 rewind
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
rewind方法只是簡單的將position的值重置,這樣可以從緩衝區開始位置讀取資料。
2.6 mark()和reset()方法
2.6.1 mark():標記當前position的位置,reset()將position返回到標記的位置。
import java.nio.ByteBuffer;
public class Test02 {
public static void main(String[] args) {
ByteBuffer bb = ByteBuffer.allocate(10);
bb.put("abcd".getBytes());
bb.flip();
byte[] b = new byte[2];
bb.get(b,0,2);//取出兩個位元組
System.out.println("position:"+bb.position());
bb.mark();//標記當前position的位置
System.out.println(new String(b,0,2));
bb.get(b,0,2);//再取出兩個位元組
System.out.println("再取出兩個位元組後的position:"+bb.position());
bb.reset();//返回標記的position位置
System.out.println("返回後的position:"+bb.position());
}
}
2.7 直接緩衝區和非直接緩衝區複製檔案
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.junit.Test;
public class Test03 {
/**
* 通過管道複製檔案,--非直接緩衝區
* 思路是:
* 1.建立原始檔的輸入流和目標檔案的輸出流
* 2.分別衝輸入輸出流中建立各自的管道
* 3.建立緩衝區,通過緩衝區,從輸入管道中讀取原始檔內容到緩衝區中,再將緩衝區中的內容寫道輸出管道中
* 4.關閉相應的資源
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//建立輸入流,讀取圖片
FileInputStream is = new FileInputStream("1.jpg");
//建立輸出流,輸出圖片
FileOutputStream os = new FileOutputStream("2.jpg");
//建立通道
FileChannel inChannel = is.getChannel();
FileChannel outChannel = os.getChannel();
//通過緩衝區將資料從輸入通道,讀到輸出通道
ByteBuffer bb = ByteBuffer.allocate(1024);
while(inChannel.read(bb) != -1){
bb.flip();//上面寫入緩衝區後,需要重置Position位置,使下面可以從頭開始讀緩衝區
outChannel.write(bb);
bb.clear();//上面讀後,需要重置,使下一次可以從頭寫入緩衝區
}
//關閉
outChannel.close();
inChannel.close();
os.close();
is.close();
}
/**
* 通過管道複製檔案 ----直接緩衝區
* 思路:
* 1.通過工廠方法建立原始檔和目標檔案的管道
* 2.建立各自的對映緩衝區
* 3.從讀緩衝區中讀取資料到寫入緩衝區中
* @throws IOException
*/
@Test
public void test() throws IOException{
//直接建立檔案管道
FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//建立檔案對映
MappedByteBuffer inmap = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outmap = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
//操作緩衝區
byte[] b = new byte[inmap.limit()];
inmap.get(b);
outmap.put(b);
//關閉資源
outChannel.close();
inChannel.close();
}
}
2.8 多緩衝區讀取檔案
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class Test04 {
/**
* 多緩衝區讀取檔案
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//建立檔案輸入流
//RandomAccessFile file = new RandomAccessFile("test01.txt", "rw");
FileInputStream file = new FileInputStream(new File("test01.txt"));
//建立管道
FileChannel channel = file.getChannel();
//建立緩衝區
ByteBuffer buf1 = ByteBuffer.allocate(100);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
//緩衝區陣列
ByteBuffer[] bs = new ByteBuffer[]{buf1,buf2};
//從管道讀取資料到緩衝區中
channel.read(bs);
//讀出緩衝區內容
System.out.println(new String(buf1.array(),0,buf1.limit()));
System.out.println("------------------");
System.out.println(new String(buf2.array(),0,buf2.limit()));
}
}