Java NIO學習筆記三------Chanel的四種實現篇

FileChannel

FileChannel是什麼

FileChannel是一個連接到文件的通道,可以通過文件通道讀寫文件。它無法設置爲非阻塞模式,總是運行在阻塞模式下。

打開FileChannel

我們可以通過使用一個InputStream、OutputStream或RandomAccessFile來獲取一個FileChannel實例。例如:

RandomAccessFile aFile = new RandomAccessFile("D:/demo/data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

讀FileChannel

調用FileChannel.read()方法,例如:

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buf);

read()方法返回的int值表示了有多少字節被讀到了Buffer中。如果返回-1,表示到了文件末尾。

寫FileChannel

調用FileChannel.write()方法,例如:

String newData = "Some data";

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();

while(buf.hasRemaining()) {
    channel.write(buf);
}

因爲無法保證write()方法一次能向FileChannel寫入多少字節,因此需要重複調用write()方法,直到Buffer中已經沒有尚未寫入通道的字節。

關閉FileChannel

用完FileChannel後必須將其關閉,例如:

channel.close();

FileChannel的位置

調用position()方法可以獲取FileChannel的當前位置,調用position(long pos)方法設置FileChannel的當前位置。例如:

long pos = channel.position();
channel.position(pos + 100);

如果將位置設置在文件結束符之後,然後從通道中讀數據,讀方法將返回-1 ,也就是文件結束標誌。 
如果將位置設置在文件結束符之後,然後向通道中寫數據,文件將撐大到當前位置並寫入數據。這可能導致“文件空洞”,磁盤上物理文件中寫入的數據間有空隙。

獲取文件的大小

long fileSize = channel.size();

截取文件

調用FileChannel.truncate()方法,截取文件時,文件中指定長度後面的部分將被刪除。如:

channel.truncate(1024);

強制寫入磁盤

操作系統一般會將數據緩存在內存中,寫入到FileChannel裏的數據不一定會即時寫到磁盤上。調用force()方法可以將通道里尚未寫入磁盤的數據強制寫到磁盤上。 
force()方法有一個boolean類型的參數,true表示同時將文件元數據(權限信息等)寫到磁盤上,例如:

channel.force(true);

SocketChannel

SocketChannel是什麼

SocketChannel是一個連接到TCP網絡套接字的通道。

打開 SocketChannel

SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://www.xxx.com", 80));

關閉 SocketChannel

socketChannel.close();

讀SocketChannel

同讀FileChannel。

寫SocketChannel

同寫FileChannel。

非阻塞模式下的連接

非阻塞模式下調用connect(),該方法可能在連接建立之前就返回了。爲了確定連接是否建立,可以調用finishConnect()方法。

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://www.xxx.com", 80));

while(!socketChannel.finishConnect() ){
    // wait, or do something else
}

非阻塞模式下的讀

非阻塞模式下,read()方法在尚未讀到任何數據時可能就返回了。所以需要關注它的int返回值,它會告訴你讀取了多少字節。

非阻塞模式下的寫

非阻塞模式下,write()方法在尚未寫出任何數據時可能就返回了。所以需要在循環中調用write()。

ServerSocketChannel

ServerSocketChannel是什麼

ServerSocketChannel 是一個可以監聽新進來的TCP連接的通道,就像標準IO中的ServerSocket一樣。

打開 ServerSocketChannel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

關閉 ServerSocketChannel

serverSocketChannel.close();

監聽新進來的連接

用ServerSocketChannel.accept()方法監聽新進來的連接。當 accept()方法返回的時候,它返回一個包含新進來的連接的 SocketChannel。因此,accept()方法會一直阻塞到有新連接到達。

while(true){
    SocketChannel socketChannel = serverSocketChannel.accept();

    // do something
}

如果是非阻塞模式,accept()方法會立刻返回,如果還沒有新進來的連接,返回的將是null。 因此,需要檢查返回的SocketChannel是否是null.

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(80));
serverSocketChannel.configureBlocking(false);

while(true) {
    SocketChannel socketChannel = serverSocketChannel.accept();

    if (socketChannel != null) {
        //do something
    }
}

DatagramChannel

DatagramChannel是什麼

DatagramChannel是一個能收發UDP包的通道。因爲UDP是無連接的網絡協議,所以不能像其它通道那樣讀取和寫入。它發送和接收的是數據包。

打開 DatagramChannel

DatagramChannel channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(9000));

接收數據

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);

發送數據

String newData = "Some data";

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());
buf.flip();

int bytesSent = channel.send(buf, new InetSocketAddress("www.xxx.com", 9000));

連接

由於UDP是無連接的,連接到特定地址並不會像TCP通道那樣創建一個真正的連接,而是鎖住DatagramChannel ,讓其只能從特定地址收發數據。

channel.connect(new InetSocketAddress("www.xxx.com", 9000));

當連接後,也可以使用read()和write()方法,就像在用傳統的通道一樣,只是在數據傳送方面沒有任何保證。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章