目录:
java Nio(一) : Nio 和Io 的区别
java Nio(二): Buffer(缓冲区)的数据存取
java Nio(三):直接缓冲区 和 非直接缓冲区
java Nio(四) :通道(Channel)
java Nio(五) : 字符集:CharSet
Channel 可以将指定的文件 或者 部分 全部映射成 Buffer
程序不能直接访问 Channel中的数据 ,读和写 都不行,Channel只能和Buffer 进行交互。
/**
* 1,通道(Channel):由java.nio.channels包定义的。Channel表示 IO 元与目标打开的连接。
* Channel本身不能直接访问数据,Channel只能和Buffer配合使用
* 2,通道的实现类:
* java.nio.channels.channel 接口:
* --FileChannel
* --SocketChannel
* --ServerSocketChannel
* --DatagramChannel
* 3,获取通道
* 1> java 针对支持通道的类提供了getChannel()方法
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile
* 网络IO:
* Socket
* ServerSocket
* DatagramSocket
* 2> 在JDK 1.7 中的NIO.2 针对各个通道提供了静态方法open()
* 3> 在JDK 1.7 中的NIO.2 的 Files 工具类的 newByteChannel()
*
* 4,通道之间的数据传输(直接缓冲区)
* transferFrom(......)
* 从给定的字节通道中将字节传输到该通道的文件中。
* transferTo(......)
* 将通道中的字节传输到给定的可写字节的通道。
*
* 5,分散(Scatter) 和聚集 (Gather)
*
* 分散读取(Scattering Reads) : 是指从Channel中读取的数据分散到多个Buffer中。
* 从Channel中读取的数据依次将Buffer填满。
* 聚集写入(Gathering Writes) : 是指将多个 Buffer 照片给你的数据“聚集”到Channel
* 按照缓冲区的顺序,写入position 到 limit之间的数据。
*/
下面看一下使用通道 完成文件的复制 :
1,利用通道完成文件的复制
//利用通道完成文件的复制(非直接缓冲区)
private static void test1() {
FileInputStream fis = null;
FileOutputStream fos = null;
FileChannel inChinnl = null;
FileChannel outChinnal = null;
try {
fis = new FileInputStream("1.exe");
fos = new FileOutputStream("3.exe");
//获取通道
inChinnl = fis.getChannel();
outChinnal = fos.getChannel();
//分配指定大小的缓冲区
ByteBuffer buff = ByteBuffer.allocate(1024);
//读取文件数据到缓冲区
while (inChinnl.read(buff) != -1) {
buff.flip();//切换到读模式
//将缓冲区的数据写入到文件中
outChinnal.write(buff);
buff.clear();
}
} catch (Exception e) {
e.printStackTrace();
try {
if (inChinnl != null)
inChinnl.close();
if (outChinnal != null)
outChinnal.close();
if (fis != null)
fis.close();
if (fos != null)
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
2,使用 直接缓冲区完成文件的复制(内存映射文件)。
//使用直接缓冲区完成文件的复制(内存映射文件)
public static void test2(){
try {
//获取通道
//目标文件,也就是要放在缓冲区的文件。 StandardOpenOption.READ:代表文件可读
FileChannel inChannel = FileChannel.open(Paths.get("1.exe"), StandardOpenOption.READ);
//目的文件,也就是要把缓冲区中的数据取出来,后面加的是READ/WRITE.代表文件可读可写。
//StandardOpenOption.CREATE:如果没有则创建新的。如果有直接覆盖
FileChannel outChannel = FileChannel.open(Paths.get("2.exe"),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//内存映射文件(也就是创建直接缓冲区)
//FileChannel.MapMode.READ_ONLY:可读
//FileChannel.MapMode.READ_WRITE:可读可写,因为这里没可写。只有可读可写。所以上面也是可读可写。
MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//直接对缓冲区进行数据读写
byte[] buf = new byte[inMap.limit()];
inMap.get(buf);
outMap.put(buf);
inChannel.close();
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
3,使用通道进行传输(其实效果和上面的一样),也是直接缓冲区.
//通道之间的数据传输(直接缓冲区)
private static void test3(){
try {
FileChannel inChannel = FileChannel.open(Paths.get("1.001"),StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("2.001"),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//下面两者选其一即可.
//将inChannel通道中的字节传输到给定的可写字节通道outChannel。
inChannel.transferTo(0,inChannel.size(),outChannel);
//从给定的inChannel通道将字节传输到outChannel。
outChannel.transferFrom(inChannel,0,inChannel.size());
inChannel.close();
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
4,分散读取 和 聚集写入
private static void test4(){
try {
FileInputStream fis = new FileInputStream("movie.mp4");
//获取通道
FileChannel outChinnel = fis.getChannel();
//创建多个缓冲区,并放入数组
ByteBuffer byt1 = ByteBuffer.allocate(1024);
ByteBuffer byt2 = ByteBuffer.allocate(1024);
ByteBuffer[] byts = {byt1,byt2};
//将文件读到 多个缓冲区(byts)中
outChinnel.read(byts);
fis.close();
outChinnel.close();
//将缓冲区改为可读模式
for (ByteBuffer buffer: byts) {
buffer.flip();
}
FileOutputStream fos = new FileOutputStream("1.mp4");
FileChannel inChannel = fos.getChannel();
//将缓冲区中的文件读出来写入到文件中.
inChannel.write(byts);
fos.close();
inChannel.close();
} catch (Exception e) {
e.printStackTrace();
}
}