2018-09-09微服务笔记(五)之 NIO

1.IO与NIO区别

NIO IO
面向流 面向缓冲
阻塞IO 非阻塞
选择器

2.三个属性

2.1 capacity:Buffer的内存固定的一个大小值,一般创建Buffer时初始化写入

2.2 position在读和写情况的分析:
                 1)写数据到Buffer中时,position表示写入数据的当前位置。position的初始值为0.当一个byte、long等数据写到Buffer后, position会向下移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1(因为position的初始值为0).
                   2)读数据到Buffer中时,position表示读入数据的当前位置,如position=2时表示已开始读入了3个byte,或从第3个byte开始读取。通过ByteBuffer.flip()切换到读模式时position会被重置为0,当Buffer从position读入数据后,position会下移到下一个可读入的数据Buffer单元。

2.3 limit在读和写情况的分析:
                   1)写数据时,limit表示可对Buffer最多写入多少个数据。
                   2)读数据时,limit表示Buffer里有多少可读数据(not null的数据),因此能读到之前写入的所有数据

2.4 demo

import java.nio.ByteBuffer;

public class Test01 {
	public static void main(String[] args) {
		//创建缓冲区,最大为1024,即capacity=1024
		ByteBuffer bb = ByteBuffer.allocate(1024);
		
		//输出属性
		System.out.println(bb.limit()); //实际可写入大小
		System.out.println(bb.capacity()); //最大大小
		System.out.println(bb.position()); //当前处理位置
		
		//放入数据
		System.out.println("------------放入数据");
		bb.put("abcd1234".getBytes());
		//输出属性
		System.out.println(bb.limit()); //当写入的时候表示最多可以写入的数据量,此时为1024
		System.out.println(bb.capacity()); //最大大小
		System.out.println(bb.position()); //当前处理位置
		
		//输出
		System.out.println("-------------输出数据");
		bb.flip();//将position位置重置为0,下面会做比较
		byte[] b = new byte[bb.limit()]; //通过flip重置position位置后,此时的limit表示缓冲区可读数据的长度,此时limit=8
		bb.get(b);
		System.out.println(new String(b,0,bb.limit()));
		
		//重复读取缓冲区数据
		System.out.println("------------重复读数据");
		bb.rewind();//重置下面会做比较
		byte[] b1 = new byte[bb.limit()];
		bb.get(b1);
		System.out.println(new String(b1,0,bb.limit()));
		
		//清空缓冲区
		System.out.println("--------清空缓冲区");
		bb.clear();
		System.out.println(bb.limit());
		System.out.println(bb.capacity());
		System.out.println(bb.position());
		System.out.println((char)bb.get());//仍可以读出数据,应为clear方法只是单纯的将三个属性重置,数据并没用清除
		
		
	}
}

2.5 clear、flip、rewind 区别

     2.5.1 clear源码

public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

     clear方法将position重置为0,将可读写范围limit设置为最大范围capacity;

2.5.2  flip

public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

将可读写范围设置为position的值,这样在读操作时,limit的值就是缓冲区中可以读写数据的大小。

将position的值重置。

2.5.3 rewind

public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }

rewind方法只是简单的将position的值重置,这样可以从缓冲区开始位置读取数据。

 

2.6 mark()和reset()方法

2.6.1 mark():标记当前position的位置,reset()将position返回到标记的位置。

import java.nio.ByteBuffer;

public class Test02 {
	public static void main(String[] args) {
		ByteBuffer bb = ByteBuffer.allocate(10);
		bb.put("abcd".getBytes());
		
		bb.flip();
		byte[] b = new byte[2];
		bb.get(b,0,2);//取出两个字节
		System.out.println("position:"+bb.position());
		bb.mark();//标记当前position的位置
		System.out.println(new String(b,0,2));
		bb.get(b,0,2);//再取出两个字节
		System.out.println("再取出两个字节后的position:"+bb.position());
		bb.reset();//返回标记的position位置
		System.out.println("返回后的position:"+bb.position());
		
	}
}

2.7 直接缓冲区和非直接缓冲区复制文件

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

import org.junit.Test;

public class Test03 {
	/**
	 * 通过管道复制文件,--非直接缓冲区
	 * 思路是:
	 * 1.创建源文件的输入流和目标文件的输出流
	 * 2.分别冲输入输出流中创建各自的管道
	 * 3.创建缓冲区,通过缓冲区,从输入管道中读取源文件内容到缓冲区中,再将缓冲区中的内容写道输出管道中
	 * 4.关闭相应的资源
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		//创建输入流,读取图片
		FileInputStream is = new FileInputStream("1.jpg");
		//创建输出流,输出图片
		FileOutputStream os = new FileOutputStream("2.jpg");
		
		//创建通道
		FileChannel inChannel = is.getChannel();
		FileChannel outChannel = os.getChannel();
		
		//通过缓冲区将数据从输入通道,读到输出通道
		ByteBuffer bb = ByteBuffer.allocate(1024);
		while(inChannel.read(bb) != -1){
			bb.flip();//上面写入缓冲区后,需要重置Position位置,使下面可以从头开始读缓冲区
			outChannel.write(bb);
			bb.clear();//上面读后,需要重置,使下一次可以从头写入缓冲区
		}
		
		//关闭
		outChannel.close();
		inChannel.close();
		os.close();
		is.close();
	}
	
	/**
	 * 通过管道复制文件  ----直接缓冲区
	 * 思路:
	 * 1.通过工厂方法创建源文件和目标文件的管道
	 * 2.创建各自的映射缓冲区
	 * 3.从读缓冲区中读取数据到写入缓冲区中
	 * @throws IOException 
	 */
	@Test
	public void test() throws IOException{
		//直接创建文件管道
		FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
		FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		
		//创建文件映射
		MappedByteBuffer inmap = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
		MappedByteBuffer outmap = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
		
		//操作缓冲区
		byte[] b = new byte[inmap.limit()];
		inmap.get(b);
		outmap.put(b);
		
		//关闭资源
		outChannel.close();
		inChannel.close();
	}
}

2.8 多缓冲区读取文件

import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Test04 {
	/**
	 * 多缓冲区读取文件
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		//创建文件输入流
		//RandomAccessFile file = new RandomAccessFile("test01.txt", "rw");
		FileInputStream file = new FileInputStream(new File("test01.txt"));
		
		//创建管道
		FileChannel channel = file.getChannel();
		
		//创建缓冲区
		ByteBuffer buf1 = ByteBuffer.allocate(100);
		ByteBuffer buf2 = ByteBuffer.allocate(1024);
		//缓冲区数组
		ByteBuffer[] bs = new ByteBuffer[]{buf1,buf2};
		
		//从管道读取数据到缓冲区中
		channel.read(bs);
		
		//读出缓冲区内容
		System.out.println(new String(buf1.array(),0,buf1.limit()));
		System.out.println("------------------");
		System.out.println(new String(buf2.array(),0,buf2.limit()));
	}
}

猜你喜欢

转载自blog.csdn.net/qiaoqiyu6416/article/details/82560011