package nio; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import org.junit.Test; public class NioTest { /** * 一.通道(channel):用于源节点与目标节点的链接在java Nio中负责缓冲区数据的传输。 * channel自己不存储数据,所以须要配合缓冲区进行传输 * 二.通道有如下几类: * FileChannel * SocketChannel * ServerSocketChannel * DatagramChannel * * 3、通道获 * 1.jdk 1.6如下 * 本地Io * FileInputStream/FileOutputStream * RandomAccessFile * 网络io * 2.在jdk 1.7之后 * FileChannel.open(path, options) * Files.newByteChannel(path, options) */ /** * 使用nio进行文件的复制 */ @Test public void test1() throws IOException { long startTime = System.currentTimeMillis(); FileInputStream fis = new FileInputStream("file.rmvb"); FileOutputStream fos = new FileOutputStream("file_back.rmvb"); FileChannel sourceChannel = fis.getChannel(); FileChannel targetChannel = fos.getChannel(); ByteBuffer buffer = ByteBuffer.allocateDirect(1024*10);// 分配直接缓冲区的方式,完成时间:4秒 buffer.isDirect(); //判断是使用直接/非直接缓冲区的方法 //ByteBuffer buffer = ByteBuffer.allocate(1024*10); //分配非直接缓冲区的方式,完成时间20秒 while (sourceChannel.read(buffer) !=-1) { buffer.flip(); targetChannel.write(buffer); buffer.clear(); } sourceChannel.close(); fos.close(); targetChannel.close(); fis.close(); long endTime= System.currentTimeMillis(); System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒"); } /** * 使用直接缓冲区完成文件的复制(内存映射文件)。 * 1.注意:使用直接内存映射,是直接使用操做系统的内存。当你开辟大量内存时,操做系统的内存使用率迅速上升。 * 可是及时文件完成了复制,内存也不会当即释放。须等到jvm的垃圾回收,因此会出现‘jvm卡内存’的状况。 * 使用这种方式虽然快,但十分的耗内存。 * 2.使用场景:在直接缓冲区能在程序性能方面带来明显好处时分配它们。 */ @Test public void test2() throws IOException { // Paths 用法: Paths.get("d:/","nio/","file.rmvb"); // StandardOpenOption :表示操做的模式 // 1.READ 可读 // 2.WRITE 可写,若是文件不存在就建立,存在就覆盖 // 3.CREATE_NEW 可写,若是文件不存在就建立,不存在就报错 long startTime = System.currentTimeMillis(); FileChannel sourceChannel = FileChannel.open(Paths.get("file.rmvb"), StandardOpenOption.READ); FileChannel targetChannel = FileChannel.open(Paths.get("file_back.rmvb"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE); //建立输出输入的映射内存 MappedByteBuffer inMapBuffer = sourceChannel.map(MapMode.READ_ONLY, 0, sourceChannel.size()); MappedByteBuffer outMapBuffer = targetChannel.map(MapMode.READ_WRITE, 0, sourceChannel.size()); //完成复制 byte[] byteArr = new byte[inMapBuffer.limit()]; inMapBuffer.get(byteArr); outMapBuffer.put(byteArr); sourceChannel.close(); targetChannel.close(); long endTime= System.currentTimeMillis(); System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒"); } /** * 通道之间的数据传输(使用直接缓冲区的方式) * @throws IOException */ @Test public void test3()throws IOException { long startTime = System.currentTimeMillis(); FileChannel sourceChannel = FileChannel.open(Paths.get("file.rmvb"), StandardOpenOption.READ); FileChannel targetChannel = FileChannel.open(Paths.get("file_back.rmvb"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE); sourceChannel.transferTo(0, sourceChannel.size(), targetChannel); //或者targetChannel.transferFrom(sourceChannel, startTime, sourceChannel.size()); sourceChannel.close(); targetChannel.close(); long endTime= System.currentTimeMillis(); System.out.println("完成复制用时:"+((endTime-startTime)/1000)+"秒"); } /** * 分散与读取 * 说明:将通道中的数据分散到多个缓冲区中(使用多个buffer进行读取),顺序写入给定的buffer */ @Test public void test4() throws IOException{ //1.获取源通道 RandomAccessFile targetFile = new RandomAccessFile("JavaNIO.pdf", "rw"); FileChannel targetChanne = targetFile.getChannel(); //2.建立buffer ByteBuffer buf1 = ByteBuffer.allocate(1024); ByteBuffer buf2 = ByteBuffer.allocate(1024); ByteBuffer[] bufArr = {buf1,buf2}; //3.建立目标通道 RandomAccessFile sourceFile = new RandomAccessFile("JavaNIO_copy.pdf", "rw"); FileChannel sourceChanne = sourceFile.getChannel(); //4.进行【分散读取】/【汇集写入】 while(targetChanne.read(bufArr) !=-1){ for (ByteBuffer buf : bufArr) { buf.flip(); } sourceChanne.write(bufArr); for (ByteBuffer buf : bufArr) { buf.clear(); } } //5.关闭 sourceChanne.close(); sourceFile.close(); targetChanne.close(); targetFile.close(); } /** * 通道用户操做本地文件的编码与解码( Charset) * 编码: 字符串 -> 字节数组 * 解码:字节数组 -> 字符组 */ @Test public void test5() throws IOException{ Charset charset = Charset.forName("utf-8"); //获取编码器 CharsetEncoder encoder = charset.newEncoder(); CharBuffer charBuffer = CharBuffer.allocate(1024); charBuffer.put("字符集 Charset学习"); charBuffer.flip(); ByteBuffer enBuffer = encoder.encode(charBuffer); for (int i = 0; i <enBuffer.limit(); i++) { System.out.println(enBuffer.get()); } System.out.println("解码:"); //获取解码器 CharsetDecoder decoder = charset.newDecoder(); enBuffer.flip(); CharBuffer deBuffer = decoder.decode(enBuffer); System.out.println(deBuffer.toString()); } }