- NIO提供的Channel表示与file或socket唯一关联,可以理解成程序通过Buffer将数据写入channel就表示将数据写入了file或socket,从channel中将数据读入Buffer就表示从file或socket中读取了数据到程序中。
- BIO是同步阻塞的,NIO是同步非阻塞的,通过将与socket唯一关联的channel注册到Selector,通过select()轮询,实现同步非阻塞。而AIO才是真正异步非阻塞的,异步表示实际的IO操作是由操作系统完成的,而不是程序完成的,操作系统完成IO后将结果返回给程序。只要是程序完成的IO操作,都是同步的。
另一篇博文NIO同步非阻塞Selector轮询实现网络socket,通过详细的注释,介绍并实现了NIO同步非阻塞的socket
详细分析见代码注释
- 向文件中写数据
package niodemo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOWriteDataToFile {
public static void main(String[] args) throws IOException {
String str = "hi,my name is fine-adj!";
//对程序来说往文件里写是输出流
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\aaa.txt");
//创建buffer
//由于file和socket存数据都是二进制的字节,所以常用的是ByteBuffer,
//创建容量capacity大小是1024个字节的buffer
int bufferSize = str.length();
ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize);
//创建channel : 获取输出流对应的channel
FileChannel fileChannel = fileOutputStream.getChannel();
//将数据写入buffer
byteBuffer.put(str.getBytes());
//!!!!!!!!!!!向buffer写入数据后buffer要调用flip,将其置为可读状态:buffer是双向的
byteBuffer.flip();
//将buffer中数据写入channel
fileChannel.write(byteBuffer); //由于channel是与文件关联的【与socket的client关联的】,所以写入channel就相当于写入文件
//关闭流
fileChannel.close();
fileOutputStream.close();
}
}
- 从文件中读数据
package niodemo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOReadFromFile {
public static void main(String[] args) throws IOException {
//从文件里读取数据
File file = new File("C:\\Users\\Administrator\\Desktop\\aaa.txt");
//对于程序来说输入流,创建文件输入流
FileInputStream fileInputStream = new FileInputStream(file);
//获取输入流对应的channel,channel是与file/socket/client唯一对应的
FileChannel fileChannel = fileInputStream.getChannel(); //!!!【file已经与channel关联了】!!!
//创建buffer,由于file/socket的数据是二进制存储的。注意创建大小的时候是这样的:(int)file.length()
ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length());
//把channel中的数据读入buffer
fileChannel.read(byteBuffer);
//byteBuffer中装入数据后,置为可读状态
byteBuffer.flip();
//程序从buffer中读数据
System.out.println(new String(byteBuffer.array()));
//关闭流
fileChannel.close();
fileInputStream.close();
}
}
- 文件拷贝
package niodemo;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class NIOCopyFileToFile {
public static void main(String[] args) throws IOException {
//对于程序来说是把数据从文件1取出来,即数据从文件1流入程序
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\aaa.txt");
//对于程序来说是把数据写入文件2,即数据从程序流入文件2
FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\bbb.txt");
//创建文件aaa的channel
FileChannel fileChannel1 = fileInputStream.getChannel();
//创建文件2的channel
FileChannel fileChannel2 = outputStream.getChannel();
//创建buffer: 共用一个buffer,因为buffer是双向的
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
//从文件1中循环取数据,写入buffer,
while (true){
//!每次向buffer写数据之前,将buffer的position属性置为0,调用clear,表示可写状态(双向的)
byteBuffer.clear(); //将position的位置置为0,表示让数据从buffer的0开始写入!!!!!!!!!!!
//将文件1中的数据写入缓冲区buffer,即将文件1对应的channel中的数据写入buffer
int read = fileChannel1.read(byteBuffer);
if(read == -1){ //循环读数据的时候,用while就一定要用break, channel的read返回-1表示channel中数据读完了。
break;
}
//buffer写入数据后置为可读状态
byteBuffer.flip(); //!!!!!!!!!!将buffer置为可读状态。(双向的)
//从buffer中将数据写入channel,即拷贝到文件2
fileChannel2.write(byteBuffer);
}
//关闭流
fileChannel1.close();
fileChannel2.close();
fileInputStream.close();
}
}