1.FileChannel
1.读的例子
public static void read(String fileName) throws IOException {
//第一种获取FileChannel的方法
/* RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
FileChannel fileChannel1= randomAccessFile.getChannel();*/
//第二种获取FileChannel的方法
File file = new File(fileName);
FileInputStream inputStream = new FileInputStream(file);
FileChannel fileChannel2=inputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(2);
int read = fileChannel2.read(byteBuffer);
while (read!=-1){
byteBuffer.flip();
System.out.println(Charset.forName("GBK").decode(byteBuffer).toString());
byteBuffer.clear();
read = fileChannel2.read(byteBuffer);
}
//直接内存 https://blog.youkuaiyun.com/qq_30055391/article/details/85009551讲过相关知识
DirectBuffer directBuffer=(DirectBuffer)byteBuffer;
directBuffer.cleaner().clean();
fileChannel2.close();
inputStream.close();
}
2.写的例子
public static void write(String fileName) throws IOException {
File file = new File(fileName);
//如果需要不覆盖 需要在后面加上 true参数
FileOutputStream fileOutputStream = new FileOutputStream(file,true);
FileChannel fileChannel = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(20);
byteBuffer.put("new new new".getBytes());
//对 position和limit进行设置 https://blog.youkuaiyun.com/qq_30055391/article/details/85009551讲过
byteBuffer.flip();
//因为不知道buffer里面的值会不会一下子写完 ,所以循环判断
while (byteBuffer.hasRemaining()){
fileChannel.write(byteBuffer);
//把channel里面的数据只保留前3位 后面的数据截掉 例子里面只会写到文件上面一个new
fileChannel.truncate(3);
System.out.println(fileChannel.size());
//强制把fileChannel里面的数据写到磁盘上面 因为有可能不是马上写入到硬盘上面的文件上面
fileChannel.force(true);
}
fileChannel.close();
fileOutputStream.close();
}
3.什么时候该使用NIO?
如果你对读取或者写入文件的速度要求特别高,可以使用NIO里面的直接内存。
如果需要文件复制,可以使用NIO里面Channel的transferTo方法,比较方便。
如果你需要读取足够大(超过1个G的文件),在JVM内存吃紧的情况下可以使用NIO里面的MappedByteBuffer(基于虚拟内存)有兴趣可以看一下 。
2.SocketChannel
阻塞模式下的例子
public static void testBlock() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
//绑定ip和端口号
socketChannel.connect(new InetSocketAddress("10.252.69.254",5049));
ByteBuffer byteBuffer = ByteBuffer.allocate(40);
//阻塞到数据被读入buffer
int alreadyread = socketChannel.read(byteBuffer);
ByteBuffer byteBufferWrite = ByteBuffer.allocate(40);
byteBuffer.put("write content".getBytes());
while (byteBufferWrite.hasRemaining()){
//阻塞到数据写入channel
int alreadyWrite =socketChannel.write(byteBuffer);
}
socketChannel.close();
}
非阻塞模式下的例子
public void testNoBlock() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
//绑定ip和端口号
socketChannel.connect(new InetSocketAddress("10.252.69.254",5049));
//设置为非阻塞模式
socketChannel.configureBlocking(false);
ByteBuffer byteBuffer = ByteBuffer.allocate(40);
//阻塞到数据被读入buffer
int alreadyread = socketChannel.read(byteBuffer);
//非阻塞模式下read方法会立即返回 所以要判断是否全部读取完毕
while (alreadyread!=-1){
socketChannel.read(byteBuffer);
}
ByteBuffer byteBufferWrite = ByteBuffer.allocate(40);
byteBuffer.put("write content".getBytes());
byteBuffer.flip();
int alreadyWrite =socketChannel.write(byteBuffer);
// 非阻塞write也会立即返回 所以要判断是否写入完成
while (alreadyWrite!=-1){
//阻塞到数据写入channel
alreadyWrite =socketChannel.write(byteBuffer);
}
socketChannel.close();
}
和传统的socket编程最大的区别就是提供了非阻塞的模式。并且可以跟selector结合实现管理多个端口的socket。但是实际情况用的不多。
3.SocketServerChannel
阻塞模式
public static void testServeSocketBlocking() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//绑定端口号
serverSocketChannel.socket().bind(new InetSocketAddress(5089));
ByteBuffer byteBuffer = ByteBuffer.allocate(50);
try {
while (true) {
//阻塞的
SocketChannel socketChannel = serverSocketChannel.accept();
int a = socketChannel.read(byteBuffer);
while (a != -1) {
byteBuffer.flip();
System.out.println(socketChannel.getLocalAddress() + ":" + Charset.forName("utf-8").decode(byteBuffer).toString());
byteBuffer.compact();
a = socketChannel.read(byteBuffer);
}
}
} finally {
serverSocketChannel.close();
}
}
非阻塞模式 修改
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
while(true){
//非阻塞直接返回 没有就直接返回null
SocketChannel socketChannel =
serverSocketChannel.accept();
if(socketChannel != null){
//do something with socketChannel...
}
}
#4.DatagramChannel
基于UDP协议的channel。
public void udpTest() throws IOException {
//UDP 协议下不需要连接 数据是按块接收的
DatagramChannel dataProgramChanne = DatagramChannel.open();
//接收数据
dataProgramChanne.bind(new InetSocketAddress(8888));
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
//如果数据包的数据过大,那么就会发生数据丢失
dataProgramChanne.receive(buf);
//发送数据
dataProgramChanne.connect(new InetSocketAddress("jenkov.com", 80));
int bytesRead = dataProgramChanne.read(buf);
int bytesWritten = dataProgramChanne.write(buf);
}