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),参数是缓冲区容量。
eg:获取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一个新的字节缓冲区(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字节缓冲区(直接Buffer)
二者的区别:
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()表示把缓冲区数据写入到通道。
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来创建管道,因为该类支持读写模式以及有大量处理文件的方法。
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
原文:https://www.cnblogs.com/fzxey/p/10828465.html