nio

nio学习笔记(三)

Posted by alonealice on 2018-02-05

FileChannel

FileChannel是一个文件的通道,可以通过它来读写文件。FileChannel无法设置为非阻塞模式。

读数据:
1
2
3
4
RandomAccessFile accessFile = new RandomAccessFile(filePath, "rw");
FileChannel fileChannel = accessFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer);

读数据时,使用read方法返回读取的数据大小,如果返回-1,就说明已经到了文件的最后。

写数据:
1
2
3
4
5
6
7
8
String text = "...";
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(text.getBytes());
buf.flip();
while(buf.hasRemaining()) {
fileChannel.write(buf);
}

write方法在写入数据时,每次写入的量是不定的,所以需要在循环体中把所有的数据写入文件。

使用完FileChannel之后,需要把通道关闭。

1
fileChannel.close();
其他方法

position(long pos):该方法可以获取通道的当前位置,同时也可以设置在特定的位置进行读写操作。

1
2
long pos = channel.position();
channel.position(pos +10);

这样操作会是数据之间存在空数据。

size:size()方法将返回该通道里数据的大小。

truncate():该方法可以截取指定的数据长度,这样就可以达到截取文件的目的。

force():该方法将通道里尚未写入磁盘的数据强制写到磁盘上。

SocketChannel

SocketChannel是一个连接到TCP网络套接字的通道,一般会使用两个地方使用到它:使用SocketChannel连接到互联网上的某台服务器,或者使用ServerSocketChannel时,当有新的连接时,会自动创建SocketChannel。

读写数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(ip, 80));

//读取数据
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = socketChannel.read(buf);

//写入数据
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(text.getBytes());
buf.flip();
while(buf.hasRemaining()) {
channel.write(buf);
}
socketChannel.close();
非阻塞模式

当设置成非阻塞模式后,就可以在异步模式下调用connect(),read() 和write()了。

1
2
3
4
5
6
7
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(ip, 80));
while(! socketChannel.finishConnect() ){
...
}

socketChannel.close();

ServerSocketChannel

ServerSocketChannel 是一个可以监听新进来的TCP连接的通道,主要用于在服务器中监听连接。

1
2
3
4
5
6
7
8
9
10
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //打来通道
serverSocketChannel.socket().bind(new InetSocketAddress(90)); //绑定端口
while(true){
SocketChannel socketChannel = //获取连接
serverSocketChannel.accept();
...
}

...
serverSocketChannel.close(); //关闭
非阻塞模式

ServerSocketChannel同样可以设置为非阻塞模式。此时,accept() 方法会立刻返回,如果还没有新进来的连接,返回的将是null。

1
2
3
4
5
6
7
8
9
10
11
12
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); //打来通道
serverSocketChannel.socket().bind(new InetSocketAddress(90)); //绑定端口
while(true){
SocketChannel socketChannel = //获取连接
serverSocketChannel.accept();
if(socketChannel!=null){
...
}
}

...
serverSocketChannel.close(); //关闭

DatagramChannel

DatagramChannel是收发UDP包的通道,因此它发送和结束的是数据包。

接收发送数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DatagramChannel channel = DatagramChannel.open();  //打开
channel.socket().bind(new InetSocketAddress(100)); //绑定接口

//接收数据
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
channel.receive(buf);

//发送数据
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(text.getBytes());
buf.flip();
int bytesSent = channel.send(buf, new InetSocketAddress(ip, 100));

Pipe

管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。

读写数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Pipe pipe = Pipe.open(); //打开通道
Pipe.SinkChannel sinkChannel = pipe.sink();
String newData = "...";
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());

buf.flip();

//写入数据
while(buf.hasRemaining()) {
sinkChannel.write(buf);
}

//读取数据
Pipe.SourceChannel sourceChannel = pipe.source();
ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = sourceChannel.read(buf);