Java NIO笔记(第三弹: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()方法,就像在用传统的通道一样,只是在数据传送方面没有任何保证。

你可能感兴趣的:(Java,NIO)