NIO总结与文件锁

package top.liangliangzi.nio;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.WritableByteChannel;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;


/**
 * NIO
 * 基类是Buffer 子类有:ByteBuffer , CharBuffer , DoubleBuffer
 *  				 FloatBuffer , IntBuffer , LongBuffer , ShortBuffer 
 *  所有的NIO操作均为异步操作,类似AJAX
 *  所有的IO操作均为同步操作。
 * @author 32081
 *
 */
public class TestNewIO {

	public static void main(String[] args) throws FileNotFoundException, IOException {
		//nio的读写数据
		//testNewIO();
		
		//从文件中读或者写数据
		//testReadWriteToFile();
		
		//更新缓冲区里面的部分值的操作
		//缓冲区里面有:0,1,2,3,4,5,6,7,8,9
		//更改为:0,1,2,6,8,10,12,14,8,9
		//testByteBuffer();
		
		
		
		//NIO复制文件三种不同的方法的效率对比
		//nioCopyFile();
		
		//文件锁
		fileLock();
		
		
	}
	

	/**
	 * 文件锁,当当前线程获取到文件锁时,不在允许别的线程访问操作此文件,直到文件锁释放
	 * 		(1.获取文件通道
	 * 		(2.文件通道获取文件锁,获取时候就锁定文件 fc.lock()
	 * 		(3.当文件锁对象调用 lock.release()或lock.close()方法时,锁才释放允许其他线程访问文件
	 * fc.tryLock();trylock锁与lock锁的区别是,前者在没有获取到锁的时候回返回Null,后者会休眠等待
	 * 测试,打开两个命令控制台,分别同时运行此文件查看
	 */
	private static void fileLock() {
		try(FileChannel fc = FileChannel.open(
			Paths.get("D:\\图片\\background\\background8.jpg"),
			StandardOpenOption.READ,StandardOpenOption.WRITE);
			){
			
			//获取文件锁
			FileLock lock = fc.lock();
			
			
			for(int i = 0;i < 10;i++) {
				Thread.sleep(1000);
				System.out.println(i);
			}
			
			//释放锁
			lock.release();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	
	
	

	/**
	 * nio的读写数据
	 * nio的三个核心变量
	 * 		(1.position ,下标,角标,要操作数据的位置,从0开始,	类似数组的index
	 * 		(2.limit 	,界限,最多能够操作的位置。比如说:容量100,但是里面只装了10个数据,最多只能读取到10个数据。10就是界限
	 * 		(3.capacity ,容量,指最多能容纳多少数据,单位是byte,类似数组的length
	 * 1.创建缓冲流
	 * 		(1.ByteBuffer bf = ByteBuffer.allocate(缓冲大小);
	 * 		(2.byte[] b = new byte[1024]; ByteBuffer bf = ByteBuffer.wrap(b);
	 * 2.用putXX/put方法写入数据
	 * 3.获取数据前需要进行   反转 bf.flip();limit = position; position = 0;mark = -1;
	 * 4.用getXX/get方法获取数据,且获取的数据是要跟插入的数据顺序一样
	 */
	private static void testNewIO() {
		ByteBuffer bf = ByteBuffer.allocate(25);
//		byte[] b = new byte[1024];
//		ByteBuffer bf1 = ByteBuffer.wrap(b);
		System.out.println(bf);
		bf.putInt(12);
		System.out.println(bf);
		bf.putDouble(12.14);
		System.out.println(bf);
		bf.putLong(1000000l);
		System.out.println(bf);
		System.out.println("------------------");
		
		//反转,limit = position;position = 0;mark = -1;
		//要取值就要反转一下
		//且取值要按照插入的顺序取值,不然值会乱
		bf.flip();
		System.out.println(bf);
		System.out.println(bf.getDouble());
		System.out.println(bf);
		System.out.println(bf.getLong());
		System.out.println(bf);
		System.out.println(bf.getInt());
		System.out.println(bf);		
	}

	
	/**
	 * 从文件中读写数据
	 * 一.写数据
	 * 		(1.文件源
	 * 		(2.获取写流FileOutputStream()
	 * 		(3.通过流打开通道FileCannel  is.getFileCannel()
	 * 		(4.创建缓冲区
	 * 		(5.写数据的时候不能调用 反转 bf.flip(),调用了之后会写入数据失败
	 * 		(6.fc.write(ByteBuffer bf);
	 * 二.读数据
	 * 		(1.文件源
	 * 		(2.获取读流FileInputStream()
	 * 		(3.打开通道 is.getFileCannel()
	 * 		(4.创建缓冲区
	 * 		(5.读取数据到缓冲区 is.read(FileCannel fc)
	 * 		(6.缓冲区进行 反转 fc.flip();
	 * 		(7.循环读取数据 
	 * 		(8.fc.hasRemaining()方式是判断position与limit之间是否还存在数据,存在返回true
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	private static void testReadWriteToFile() throws FileNotFoundException, IOException {
		//把数据写入文件中
		File file = new File("C:\\Users\\32081\\Desktop\\test.txt");
		try(FileOutputStream os = new FileOutputStream(file);){
			//打开通道
			FileChannel fc = os.getChannel();
			
			//创建缓冲
			byte[] b = new byte[] {97,98,99,100,101,102};
			ByteBuffer bf = ByteBuffer.wrap(b);
			
			//写入数据
			fc.write(bf);
			System.out.println("写入文件完成!");
			
		}catch (Exception e) {
			e.printStackTrace();
		}
		
		
		//从文件中读数据
		File file2 = new File("C:\\Users\\32081\\Desktop\\test.txt");
		try(FileInputStream is = new FileInputStream(file2)){
			//打开通道
			FileChannel channel = is.getChannel();
			
			//创建缓冲区
			ByteBuffer bf = ByteBuffer.allocate(1024);
			
			//读取数据到缓冲区
			channel.read(bf);
			
			//反转
			bf.flip();
			
			//循环遍历
			while(bf.hasRemaining()) {
				System.out.println((char)bf.get());
			}
			
		}
	}
	
	/**
	 * 缓冲区里面有:0,1,2,3,4,5,6,7,8,9
	 * 更改为:0,1,2,6,8,10,12,14,8,9
	 * 		(1.创建缓冲区并指定容量
	 * 		(2.放入数据
	 * 		(3.设置position与limit的位置;fc.position(index),fc.limit(index);
	 * 		(4.调用slice方法创建一个同步的新缓冲区,
	 * 			新缓冲区的内容将从此缓冲区的当前位置开始。 对这个缓冲区内容的更改将在新的缓冲区中可见
	 * 			,反之亦然; 两个缓冲区的位置,极限和标记值将是独立的。 
	 * 		(5.在新缓冲区中循环进行相关操作并赋值在新缓冲区,此操作相当于操作原本的缓冲区
	 * 		(6.调整position与limit的位置然后遍历输出原本的缓冲区
	 */
	private static void testByteBuffer() {
		//创建40个字节,10个整型的缓冲区
		IntBuffer bf = IntBuffer.allocate(10);
		
		//放入数据
		for(int i = 0;i < bf.capacity();i++) {
			bf.put(i);
		}
		//设置position与limit的指向
		bf.position(3);//指向第四个元素,包括本身
		bf.limit(8);//指向第九个元素但不包括本身:排他
		
		//获取新缓冲区
		IntBuffer slice = bf.slice();
		//循环操作
		for(int i = 0;i < slice.capacity();i++) {
			slice.put(slice.get(i)*2);//更新操作
		}
		
		//从新调整posistion与limit位置
		bf.position(0);
		bf.limit(bf.capacity());
		
		for(int i = 0;i < bf.capacity();i++) {
			System.out.print(bf.get(i)+" ");
		}
	}
	
	
	
	private static void nioCopyFile() throws FileNotFoundException, IOException {
		//源文件
		File source = new File("D:\\图片\\background\\background8.jpg");
		//目标文件
		File target = new File("D:\\图片\\copy.jpg");
		
		//baseCopy(source,target);//基础的NIO复制文件	耗时:48
		
		//baseAdvancedCopy(source,target);//基础进阶的NIO复制文件 耗时:10
		
		//SuperAdvancedCopy(source,target);//超进阶的NIO复制文件 耗时:13
		
	}

	
	/**
	 * 超进阶的NIO复制文件
	 * 		(1.调用Files工具类的copy方法copy(Path source, Path target, CopyOption... options)
	 * 		(2.source:源的Path对象		File.toPath()即可
	 * 			target:目标的Path对象	File.toPath()
	 * 			options: 调用枚举类StandardCopyOption的属性
	 * 						ATOMIC_MOVE 		将文件作为原子文件系统操作移动。  
	 * 						COPY_ATTRIBUTES 	将属性复制到新文件。  
	 * 						REPLACE_EXISTING 	替换现有文件(如果存在)。  
	 * @param source
	 * @param target
	 * @throws IOException
	 */
	private static void SuperAdvancedCopy(File source, File target) throws IOException {
		Long start = System.currentTimeMillis();
		Files.copy(source.toPath(), target.toPath(),
				StandardCopyOption.COPY_ATTRIBUTES,StandardCopyOption.REPLACE_EXISTING);
		Long end = System.currentTimeMillis();
		System.out.println("SuperAdvancedCopy超进阶的NIO复制文件耗时:" + (end - start));
	}





	/**
	 * 基础进阶的NIO复制文件
	 * 		(1.创建输入输出流
	 * 		(2.获取输出跟输出流的通道
	 * 		(3.输入通道里面的transferTo(long position, long count,WritableByteChannel target)
	 * 		方法一行搞定复制,position:开始位置		一般为0
	 * 						count:结束位置		一般为输入通道.size()
	 * 						target:写出通道
	 * @param source
	 * @param target
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static void baseAdvancedCopy(File source, File target) throws FileNotFoundException, IOException {
		Long start = System.currentTimeMillis();
		try(FileInputStream is = new FileInputStream(source);
			FileOutputStream os = new FileOutputStream(target);
			){
			//打开两个通道
			FileChannel fis = is.getChannel();
			FileChannel fos = os.getChannel();
			
			//一行搞定复制
			fis.transferTo(0, fis.size(), fos);
			
			Long end = System.currentTimeMillis();
			System.out.println("baseAdvancedCopy基础进阶新IO的复制文件耗时:" + (end - start));
		}
	}





	/**
	 * 基础的NIO复制文件
	 * 		(1.创建输入输出流
	 * 		(2.获取输出跟输出流的通道
	 * 		(3.创建缓冲区
	 * 		(4.while循环进行复制操作,每次循环都必须重置position与limit的下标
	 * 			调用bf.clear(),因为每次循环都传输了一整个缓冲区大小的数据,
	 * 			此时position与limit均已经指向缓冲区的末尾,即posiotion == capacity == limit
	 * 		(5.利用通道读取数据传输到缓冲区
	 * 		(6.缓冲区进行反转操作,然后利用写通道把缓冲区的数据写出
	 * @param source	文件源
	 * @param target	目标文件
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static void baseCopy(File source, File target) throws FileNotFoundException, IOException {
		Long start = System.currentTimeMillis();
		try(FileInputStream is = new FileInputStream(source);
			FileOutputStream os = new FileOutputStream(target);
			){
			//打开两个通道
			FileChannel fis = is.getChannel();
			FileChannel fos = os.getChannel();
			
			//创建缓冲区
			ByteBuffer bf = ByteBuffer.allocate(1024);
			
			while(true) {
				//重置limit与position,因为每次循环
				//position与limit都会移动到缓冲区最后,所以需要重置
				bf.clear();
				
				int read = fis.read(bf);
				if(read == -1) {	//读完没有资源了就退出循环
					break;
				}
				
				//缓冲区进行反转
				bf.flip();
				//写出资源
				fos.write(bf);
			}
			Long end = System.currentTimeMillis();
			System.out.println("baseCopy基础新IO的复制文件耗时:" + (end - start));
		}
	}




	
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值