java的nio入门基础

Posted 白日梦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java的nio入门基础相关的知识,希望对你有一定的参考价值。

1.nio的简介

nio的FileChannel类可以获取的方法有 FileInputStream和FileOutputStream以及RandomAccessFile的getChannel方法,或者FileChannel类的open方法等获取,SocketChannel,ServerSocketChannel,DatagramChannel,同样可以Socket,ServerSocket的getChannel方法和open方法(tcp)等获取,DatagramChannel可以通过open方法获取(udf)等方法获取,Pipe也可以同过open等方法获取,他们只是建立通道,并不参与数据的输入和输出,输入和输出是buffer完成的,buffer有直接缓存区和非直接缓存区两种,直接缓存建立在物理内存上的,建立和销毁allocateDirect的空间的开销比较大,传递的效率要比非直接缓冲区要好(因为直接缓存区只需要复制一次,而非直接缓存区需要复制两次,直接缓存区较非直接缓存区减少了一次复制),所以通常用于传递allocateDirect的空间开创的比较大的时候,用利于传输比较大的文件,但是太大例如超过几个G,那么可以通过分段的方式来传输,非直接缓存区是建立在堆上的,受到jvm的限制。

2.Buffer

常用的方法有position limit capacity  mark  reset  rewind  hasRemaining remaining  flip  clear isDirect等以及get,put方法(position会相应的移动)但是又较多的重载方法,没有参数的表示返回游标位置的数据或者放入数据,数组表示向数组中放入数据或者向数组中写入数据。

public class ByteBufferTest {
	public static void main(String[] args) {
		ByteBuffer buffer = ByteBuffer.allocate(10);
		if (!buffer.isDirect()) {
			System.out.println("非直接缓冲区");// 非直接缓冲区
		}
		System.out.println(buffer.position());// 位置0
		System.out.println(buffer.limit());// 界限10
		System.out.println(buffer.capacity());// 开辟的空间10
		buffer.put((byte) ‘a‘);
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置1
		System.out.println(buffer.limit());// 界限10
		System.out.println(buffer.capacity());// 开辟的空间10
		byte[] bys = { (byte) ‘b‘, (byte) ‘c‘ };
		buffer.put(bys);
		buffer.mark();
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置3
		System.out.println(buffer.limit());// 界限10
		System.out.println(buffer.capacity());// 开辟的空间10
		buffer.reset();
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置1
		System.out.println(buffer.limit());// 界限10
		System.out.println(buffer.capacity());// 开辟的空间10
		buffer.flip();// 将limit设置为当前位置,position设置为0
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置0
		System.out.println(buffer.limit());// 界限1
		System.out.println(buffer.capacity());// 开辟的空间10
		buffer.rewind();// limit不变,position变为0,且去除mark
		buffer.flip();
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置0
		System.out.println(buffer.limit());// 界限0
		System.out.println(buffer.capacity());// 开辟的空间10
		try {
			buffer.reset();
			System.out.println("-------------");
			System.out.println(buffer.position());
			System.out.println(buffer.limit());
			System.out.println(buffer.capacity());
		} catch (Exception e) {
			System.out.println("mark标记不存在了");
		}
		buffer.limit(3);
		buffer.position(3);//position<=limit<=capacity
		buffer.flip();
		System.out.println(buffer.remaining());//position与limit之间还剩多少元素3
		System.out.println("-------------");
		System.out.println(buffer.position());// 位置0
		System.out.println(buffer.limit());// 界限3
		System.out.println(buffer.capacity());// 开辟的空间10
		while(buffer.hasRemaining()){//position和limit之间是否还有元素
			System.out.println((char)buffer.get());// a b c
		}
		System.out.println("------------");
		System.out.println(buffer.position());// 位置3
		System.out.println(buffer.limit());// 界限3
		System.out.println(buffer.capacity());// 开辟的空间10
		byte[] bys1 = { (byte) ‘d‘, (byte) ‘e‘, (byte) ‘f‘};
		buffer.limit(9);
		buffer.put(bys1);
		buffer.position(7);
		/*limit变为等于capacity,position的位置等于limit-position,在limit-position的
		数据相应的往前移覆盖position开始的同样多的数据*/
		buffer.compact();
		System.out.println("------------");
		System.out.println(buffer.position());// 位置2
		System.out.println(buffer.limit());// 界限10
		System.out.println(buffer.capacity());// 开辟的空间10
		while(buffer.hasRemaining()){//position和limit之间是否还有元素
			System.out.println((char)buffer.get());// c d e f 4个空格
		}
	}
}

 其他的buffer类似

3.FileChannel

public class FileChannelTest {
	public static void main(String[] args) throws IOException {

		// 非直接缓冲区
		// 方式1
		FileChannel channel1 = null;
		FileChannel channel2 = null;
		try {
			channel1 = new FileInputStream("1.txt").getChannel();
			channel2 = new FileOutputStream("3.txt").getChannel();
			ByteBuffer allocate = ByteBuffer.allocate(1024);
			while (channel1.read(allocate) != -1) {
				allocate.flip();
				channel2.write(allocate);
				allocate.clear();
			}
		} finally {
			channel1.close();
			channel2.close();
		}
		// 方式2
		FileChannel channel3 = new RandomAccessFile("1.txt", "r").getChannel();
		FileChannel channel4 = new RandomAccessFile("4.txt", "rw").getChannel();
		ByteBuffer allocate1 = ByteBuffer.allocate(1024);
		while (channel3.read(allocate1) != -1) {
			allocate1.flip();
			channel4.write(allocate1);
			allocate1.clear();
		}
		channel3.close();
		channel4.close();
		// 方式3
		FileChannel open1 = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
		// StandardOpenOption.CREATE
		// 有就覆盖,没有就创建,StandardOpenOption.CREATE_NEW有就报错,没有就创建
		FileChannel open2 = FileChannel.open(Paths.get("5.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE,
				StandardOpenOption.CREATE_NEW);
		ByteBuffer allocate2 = ByteBuffer.allocate(1024);
		while (open1.read(allocate2) != -1) {
			allocate2.flip();
			open2.write(allocate2);
			allocate2.clear();
		}
		open1.close();
		open2.close();
		// 直接缓冲区
		// 方式1
		FileChannel channel5 = null;
		FileChannel channel6 = null;
		try {
			channel5 = new FileInputStream("1.txt").getChannel();
			channel6 = new FileOutputStream("6.txt").getChannel();
			MappedByteBuffer map = channel5.map(MapMode.READ_ONLY, 0, channel5.size());
			channel6.write(map);
		} finally {
			channel5.close();
			channel6.close();
		}
		// 方式2
		FileChannel open3 = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
		// StandardOpenOption.CREATE有就覆盖,没有就创建,StandardOpenOption.CREATE_NEW有就报错,没有就创建
		FileChannel open4 = FileChannel.open(Paths.get("7.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE,
				StandardOpenOption.CREATE_NEW);
		ByteBuffer allocate3 = ByteBuffer.allocateDirect(1024);
		while (open3.read(allocate3) != -1) {
			allocate3.flip();
			open4.write(allocate3);
			allocate3.clear();
		}
		open3.close();
		open4.close();
		// 方式3
		FileChannel open5 = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
		// StandardOpenOption.CREATE
		// 有就覆盖,没有就创建,StandardOpenOption.CREATE_NEW有就报错,没有就创建
		FileChannel open6 = FileChannel.open(Paths.get("8.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE,
				StandardOpenOption.CREATE_NEW);
		MappedByteBuffer map1 = open5.map(MapMode.READ_ONLY, 0, open4.size());
		MappedByteBuffer map2 = open6.map(MapMode.READ_WRITE, 0, open4.size());
		// open4.size()不能太大否则会超出int的范围
		byte[] dst1 = new byte[(int) open4.size()];
		// 将数据放入dst1中
		map1.get(dst1);
		// 将dst1写入文件中
		map2.put(dst1);
		open5.close();
		open6.close();
		// 方式4
		FileChannel open7 = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
		// StandardOpenOption.CREATE
		// 有就覆盖,没有就创建,StandardOpenOption.CREATE_NEW有就报错,没有就创建
		FileChannel open8 = FileChannel.open(Paths.get("9.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE,
				StandardOpenOption.CREATE_NEW);
		open7.transferTo(0, open7.size(), open8);
		// open8.transferTo(position, count, target)
		open7.close();
		open8.close();
	}
}

4.直接缓存区域与非直接缓冲区的效率比较

public static void main(String[] args) throws IOException {
       long  start=System.currentTimeMillis();
       String filePath="F:/test/1.wmv";
       FileChannel inch1 = new  FileInputStream(filePath).getChannel();
       FileChannel outch1 = new  FileOutputStream("2.wmv").getChannel();
       ByteBuffer bf1 = ByteBuffer.allocate(2);
       while(inch1.read(bf1)!=-1){
           bf1.flip();
           outch1.write(bf1);
           bf1.clear();
       }
       inch1.close();
       outch1.close();
       long end=System.currentTimeMillis();
       System.out.println(end-start);//189388
     //当allocate为4的时候,时间为100988
System.gc(); System.runFinalization(); start=System.currentTimeMillis(); FileChannel inch2 = new FileInputStream(filePath).getChannel(); FileChannel outch2 = new FileOutputStream("3.wmv").getChannel(); ByteBuffer bf2 = ByteBuffer.allocateDirect(2); while(inch2.read(bf2)!=-1){ bf2.flip(); outch2.write(bf2); bf2.clear(); } inch2.close(); outch2.close(); end=System.currentTimeMillis(); System.out.println(end-start);//190209 } }

 

public static void main(String[] args) throws IOException {
       long  start=System.currentTimeMillis();
       String filePath="F:/test/1.wmv";
       FileChannel inch1 = new  FileInputStream(filePath).getChannel();
       FileChannel outch1 = new  FileOutputStream("2.wmv").getChannel();
       ByteBuffer bf1 = ByteBuffer.allocate(10000);
       while(inch1.read(bf1)!=-1){
           bf1.flip();
           outch1.write(bf1);
           bf1.clear();
       }
       inch1.close();
       outch1.close();
       long end=System.currentTimeMillis();
       System.out.println(end-start);//200
       System.gc();
       System.runFinalization();
       start=System.currentTimeMillis();
       FileChannel inch2 = new  FileInputStream(filePath).getChannel();
       FileChannel outch2 = new  FileOutputStream("3.wmv").getChannel();
       ByteBuffer bf2 = ByteBuffer.allocateDirect(10000);
       while(inch2.read(bf2)!=-1){
           bf2.flip();
           outch2.write(bf2);
           bf2.clear();
       }
       inch2.close();
       outch2.close();
       end=System.currentTimeMillis();
       System.out.println(end-start);//90
       System.gc();
       System.runFinalization();
       start=System.currentTimeMillis();
       FileChannel inch3 = new  FileInputStream(filePath).getChannel();
       FileChannel outch3 = new  FileOutputStream("4.wmv").getChannel();
       inch3.transferTo(0, inch3.size(), outch3);
       inch3.close();
       outch3.close();
       end=System.currentTimeMillis();
       System.out.println(end-start);//33
}
}

 

5.SocketChannel

待续

以上是关于java的nio入门基础的主要内容,如果未能解决你的问题,请参考以下文章

Java入门与基础(实例之文件)

即时通讯开发之Java NIO入门知识分享

NIO 入门

六.Netty入门到超神系列-Java NIO零拷贝实战

Java基础入门五)之方法以及递归算法

Java.nio:最简洁的递归目录删除