1. 程式人生 > 實用技巧 >java NIO的基本用法

java NIO的基本用法

NIO的基本用法

1、什麼是NIO

一種新IO流,可以實現對檔案的讀寫操作,效率比IO流高

2、NIO和IO的區別

  • IO是面向流(Stream)的;NIO是面向通道(Channel)和緩衝區(Buffer)的,資料總是從通道讀取到緩衝區中,或者從緩衝區寫入到通道中

  • IO流是阻塞的,這意味著,當一個執行緒呼叫read() 或 write()時,該執行緒被阻塞,直到有一些資料被讀取,或資料完全寫入。該執行緒在此期間不能再幹任何事情了。NIO是非阻塞的,NIO的非阻塞模式,使一個執行緒從某通道傳送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會獲取。而不是保持執行緒阻塞,所以直至資料變得可以讀取之前,該執行緒可以繼續做其他的事情。

3、NIO中的Channel的主要實現

  • FileChannel:檔案通道

  • DatagramChannel:通過 UDP 讀寫網路中的資料通道。

  • SocketChannel:通過 TCP 讀寫網路中的資料

  • ServerSocketChannel:可以監聽新進來的 TCP 連線,對每一個新進來的連線都會建立一個 SocketChannel

我們這裡主要講解FileChannel

4、NIO中的關鍵Buffer實現

NIO中的關鍵Buffer實現有:ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer,分別對應基本資料型別: byte, char, double, float, int, long, short。當然NIO中還有MappedByteBuffer, HeapByteBuffer, DirectByteBuffer等這裡先不進行陳述。

5、緩衝區Buffer的基本屬性

  • 容量 (capacity) :表示 Buffer 最大資料容量,緩衝區容量不能為負,並且建立後不能更改。

  • 限制 (limit) :第一個不應該讀取或寫入的資料的索引,即位於 limit 後的資料不可讀寫。緩衝區的限制不能為負,並且不能大於其容量。

  • 位置 (position):下一個要讀取或寫入的資料的索引。緩衝區的位置不能為負,並且不能大於其限制

6、FileChannel用法(實現文字複製)

a、方式一(讀取檔案到緩衝區)

public static void main(String[] args) throws IOException {
//位元組輸入流
FileInputStream fileInputStream=new FileInputStream(new File("object02/src/a.txt"));
//位元組輸出流
FileOutputStream fileOutputStream=new FileOutputStream(new File("object02/src/b.txt"));
//獲取通道,通過檔案對應io流獲取對應通道
FileChannel fromFileChannel=fileInputStream.getChannel();
FileChannel toFileChannel=fileOutputStream.getChannel();
//建立緩衝區並分配空間
ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
//讀取檔案資料到緩衝區
while (fromFileChannel.read(byteBuffer)!=-1){
//設定緩衝區為讀模式(看原始碼)
byteBuffer.flip();
//寫資料
toFileChannel.write(byteBuffer);
//清空緩衝區(不清空緩衝區無法進行下一次讀取,因為position=capacity,看原始碼)
byteBuffer.clear();
}
//關閉資源
fileInputStream.close();
fileOutputStream.close();
fromFileChannel.close();
toFileChannel.close();
}

b、方式二(通過channel的對映記憶體實現)

@Test
public void testCopyFile02() throws IOException
{
//建立1.mp4的通道(就是連線點), StandardOpenOption.READ開啟讀許可權
FileChannel fileChannelA=FileChannel.open(Paths.get("d:/1.mp4"), StandardOpenOption.READ);
FileChannel fileChannelB=FileChannel.open(Paths.get("d:/2.mp4"),
StandardOpenOption.WRITE, //寫許可權
StandardOpenOption.READ, //讀許可權
StandardOpenOption.CREATE);//建立一個新的檔案,如果該檔案已經存在失敗
//建立fileChannelA通道的對映記憶體,MapMode.READ_ONLY:只讀,從0讀到fileChannelA.size()
MappedByteBuffer inMappedBuf = fileChannelA.map(MapMode.READ_ONLY, 0, fileChannelA.size());
//建立fileChannelB通道的對映記憶體,MapMode.READ_WRITE:讀寫,從0讀到fileChannelA.size()
MappedByteBuffer outMappedBuf = fileChannelB.map(MapMode.READ_WRITE, 0, fileChannelA.size());
//建立一個位元組陣列
byte[] dst = new byte[inMappedBuf.limit()];
//從對映記憶體讀取資料
inMappedBuf.get(dst);
//將讀取的資料寫到d:/2.mp4
outMappedBuf.put(dst);
//關閉通道
fileChannelA.close();
fileChannelB.close();
}

c、方式三(方式二的簡化)

    @Test
public void testCopyFile03() throws IOException
{
//建立1.mp4的通道(就是連線點), StandardOpenOption.READ開啟讀許可權
FileChannel fileChannelA=FileChannel.open(Paths.get("d:/1.mp4"), StandardOpenOption.READ);
FileChannel fileChannelB=FileChannel.open(Paths.get("d:/2.mp4"),
StandardOpenOption.WRITE, //寫許可權
StandardOpenOption.READ, //讀許可權
StandardOpenOption.CREATE);//建立一個新的檔案,如果該檔案已經存在失敗
//複製fileChannelA的內容到fileChannelB
fileChannelB.transferFrom(fileChannelA, 0, fileChannelA.size());
//關閉通道
fileChannelA.close();
fileChannelB.close();
}