NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的做用和目的,但实现方式不一样,NIO主要用到的是块,因此NIO的效率要比IO高不少。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另外一套就是网络编程NIO。编程
Buffer
是一个抽象类;
子类有:ByteBuffer
,CharBuffer
,DoubleBuffer
,FloatBuffer
,IntBuffer
,LongBuffer
,ShortBuffer
核心类(经常使用类):ByteBuffer
和CharBuffer
其中ByteBuffer
有一个子类MappedByteBuffer
(MappedByteBuffer
类可以将文件直接映射到内存中,那么这样咱们就能够像访问内存同样访问文件,很是方便)网络
由于Buffer都是抽象类,没法直接实例化。建立缓冲区要调用XxxBuffer allocate(int capacity),XxxBuffer allocateDirect(int capacity),参数是缓冲区容量。app
eg:获取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一个新的字节缓冲区(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字节缓冲区(直接Buffer)dom
两者的区别:异步
public static void main(String[] args) { CharBuffer buffer = CharBuffer.allocate(8); // Buffer已经准备好了向Buffer中写数据 写模式 System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 0 buffer.put('a'); buffer.put('b'); buffer.put('c'); System.out.println("------------------------"); System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 3 System.out.println("------------------------"); // 切换模式 ,limit变为position的位置而后将position变为0 buffer.flip(); System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 3 System.out.println("position:" + buffer.position()); // 0 System.out.println("------------------------"); System.out.println("------------------"); buffer.clear(); // 将postion 清 0 ,将limit = capacity System.out.println("capacity:" + buffer.capacity()); // 8 System.out.println("limit:" + buffer.limit()); // 8 System.out.println("position:" + buffer.position()); // 0 // 注意: 调用clear方法只是将读模式改成写模式,并不会清空缓冲区的数据 }
Channel原理相似于传统的流对象,区别在于:
1.Channel可以将指定的部分或者所有文件映射到内存中
2.程序若是想要读取Channel中的数据,不可以直接读写,必须通过Buffer
简单来讲:Channel经过Buffer(缓冲区)进行读写操做。read()表示读取通道数据到缓冲区,write()表示把缓冲区数据写入到通道。ide
inChannel.map(mode, position, size)
MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
public static void main(String[] args) throws IOException { File srcFile = new File("nio-a.txt"); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(new File("nio-b.txt")); // 获取Channel对象 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); // 获取MapByteBuffer对象 MappedByteBuffer mapBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length()); //字符集解码器 Charset charset = Charset.forName("GBK"); outChannel.write(mapBuffer); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(mapBuffer); System.out.println(charBuffer); }
通道能够异步读写,异步读写表示通道执行读写操做时,也能作别的事情,解决线程阻塞。若是使用文件管道(FileChannel),建议用RandomAccessFile来建立管道,由于该类支持读写模式以及有大量处理文件的方法。post
public static void main(String[] args) throws Exception { File f = new File("nio-a.txt"); RandomAccessFile raf = new RandomAccessFile(f, "rw"); FileChannel channel = raf.getChannel(); MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, f.length()); // raf.seek(f.length()); channel.position(f.length()); channel.write(mapBuffer); }
理解为现实生活的编码表对象
当使用NIO来获取文件内容时,若是是文本数据,那么须要进行转码,才能查看正确内容,这就须要解码器。 若是要把字符数据写入文件,须要将CharBuffer转码成ByteBuffer,这就须要编码器。编码
public static void main(String[] args) throws IOException { //匿名子对象实现FileVisitor接口 FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { System.out.println("正在访问" + path + "文件"); if(path.endsWith("NIODemo.java")){ System.out.println("恭喜您找到Java"); return FileVisitResult.CONTINUE; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException { System.out.println("准备访问" + path + "文件"); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException { System.out.println("准备访问" + path + "文件失败"); System.out.println(exc.getMessage()); return FileVisitResult.CONTINUE; } }; //访问文件树 Files.walkFileTree(Paths.get("D:\\JavaSE"), visitor); }
以上线程
@Fzxey