Java - NIO

NIO

ByteBuffer

代码1

package _ByteBuffer;

import java.util.*;
import java.nio.*;

public class _ByteBuffer_01 {
	public static void main(String args[]) {
		test01();
	}
	public static void test01() {
		//1. 获取缓冲区
		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//容量capacity = 1024的缓冲区
		//2. 向缓冲区添加数据
		byteBuffer.put("I Love You".getBytes());
		//3. 转换成读模式
		byteBuffer.flip();
		//4. 从Buffer中读取数据
		//4.1 读取一个字节
		//byte b = byteBuffer.get();
		//System.out.println((char)b);
		//4.2 读取多个字节
		//这里必须先将读取单个字符注释掉,因为执行一次get后相当于指针已经指向了下标1,
		//所以再继续读取buffer.limit个字符后越界.报错BufferUnderflowException
		byte[] byt = new byte[byteBuffer.limit()];
		byteBuffer.get(byt);
		System.out.println(new String(byt));
		//5. 调用clear()方法或者compact()方法
		byteBuffer.clear();//清空整个缓冲区
		//byteBuffer.compact();//只清除已经读过的数据,任何未读的数据都会被移动到缓冲区的起始处,新写入的数据将放到缓冲区未读数据的后面。
	}
}

代码2

package _ByteBuffer;

import java.util.*;
import java.nio.*;

/**
 * 
 * Buffer的capacity、position、limit
 * 
 * 缓冲区本质上时一块可以写入数据,然后可以从中读取数据的内存,这块内存被包装成NIO Buffer对象,并提供了一组方法用来方便的访问这块内存
 *
 * 为了理解Buffer的工作原理,需要熟悉它的三个属性
 * (1)capacity:容量
 * (2)position:容量开始的位置
 * (3)limit:容量结束的位置
 * 
 * position和limie的含义取决于Buffer处于读模式还是写模式,但是不管Buffer处于什么模式,capacity的含义总是相同的
 *
 */

public class _ByteBuffer_02 {
	public static void main(String args[]) {
		test01();
	}
	public static void test01() {
		//1. 
		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		//容量capacity = 1024字节,position = 0, limit = 1024
		System.out.println("position:" + byteBuffer.position());// 0
		System.out.println("limit:" + byteBuffer.limit());// 1024
		
		byteBuffer.put("Hello".getBytes());
		System.out.println(byteBuffer.position());// 5->position指向的是当前内容的结尾,方便接着往下写
		System.out.println(byteBuffer.limit());// 1024
		
		byteBuffer.put("World".getBytes());
		System.out.println(byteBuffer.position());// 10
		System.out.println(byteBuffer.limit());// 1024
		
		
		/* 2. 
		 * .filp():切换为读模式
		 * 切换到读模式之火,capacity不变,position和limit的位置发生变化
		 * position = 0, limit = 10
		 * 表示position移动到最开始的位置,而limit移动到原来的position的位置
		 * 从而避免了读取Buffer数据的时候读到null值
		 */
		byteBuffer.flip();
		System.out.println(byteBuffer.position());
		System.out.println(byteBuffer.limit());
		
		//获取单个字节
		//buffer.get();
		//获取多个字节
		byte[] data=new byte[byteBuffer.limit()];
		byteBuffer.get(data);
		System.out.println("data:"+new String(data));
		System.out.println("读取data后:"+byteBuffer.position());//从0变成了10,position相当于读字节的指针,内容读完了指到了结尾
		System.out.println("读取data后:"+byteBuffer.limit());
		
		//将position设回0,所以你可以重读Buffer中的所有数据。limit保持不变,仍然表示能从Buffer中读取多少个元素
//		buffer.rewind();
//		byte[] data1=new byte[buffer.limit()];
//		buffer.get(data1);
//		System.out.println(new String(data1));
//		System.out.println(buffer.position());//从0变成了10,position相当于读字节的指针,内容读完了指到了结尾
//		System.out.println(buffer.limit());
		
		/*
		 * clear():
		 * API中的意思是清空缓冲区
		 * 而是将缓冲区中limit和position恢复到初始状态
		 * 即limit和capacity都为1024 position是0
		 * 此时可以完成写入模式
		 */
		byteBuffer.clear();
		System.out.println("clear后:"+byteBuffer.position());
		System.out.println("clear后:"+byteBuffer.limit());
		
		//可以继续写
		byteBuffer.put("temp".getBytes());
		//继续读
		byteBuffer.flip();
		byte[] arr = new byte[byteBuffer.limit()];
		byteBuffer.get(arr);
		System.out.println("temp:"+new String(arr));
	}
}

FileChannel

代码1

package _FileChannel;

import java.util.*;
import java.io.IOException;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.io.*;

/**
 * 
 * Channel
 * 
 * Channel 类似于传统的流对象,但是和传统的流对象相比,主要有以下两个区别
 * (1)Channel可以直接将指定文件的部分或者全部映射成Buffer
 * (2)程序不能直接访问Channel中的数据,读取和写入都不可以,Channel只能与Buffer进行交互
 * 
 * Java为Channel接口提供了FileChannel、DatagramChannel、ServerSocketChannel、SocketChanllel等
 * 
 * 以FileChannel接口为例,在使用FileChannel之前,必须先将其打开,但是我们无法直接打开一个FileChannel,因此
 * 需要通过使用一个InputStream、OutputStream的getChannel()方法来返回对应Channel
 *
 */

public class _FileChannel_01 {
	public static void main(String args[]) {
		//test01();
		//test02();
		//test03();
		test04();
	}
	// 写入文本文件
	public static void test01() {
		try {
			//1. 创建文件写出流
			FileOutputStream fileOutputStream = new FileOutputStream("test1.txt");
			
			//2. 获取通道Channel
			FileChannel fileChannel = fileOutputStream.getChannel();
			
			//3. 创建缓冲流
			ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
			
			//4. 向缓冲流中放入数据
			byteBuffer.put("Hello World!\n".getBytes());
			
			//5. 转换为读模式
			byteBuffer.flip();
			
			//6. 通过通道Channel写入文件
			fileChannel.write(byteBuffer);
			
			//7. 关闭资源
			fileChannel.close();
			fileOutputStream.close();
			System.out.println("写入完成");
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
	// 文件读取
	public static void test02() {
		try {
			//创建文件输入流
			FileInputStream fileInputStream = new FileInputStream("test1.txt");
			//获取通道
			FileChannel fileChannel = fileInputStream.getChannel();
			//创建缓冲流对象
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			//利用通道将文件内容写入到buffer中
			int num = fileChannel.read(buffer);
			System.out.println(num);
			//转换为读模式
			buffer.flip();
			//利用缓冲流读取数据到控制台
			System.out.println(new String(buffer.array(), 0, num));
			byte[] byt = new byte[buffer.limit()];
			buffer.get(byt);
			System.out.println(Arrays.toString(byt));
			//关闭资源
			fileChannel.close();
			fileInputStream.close();
			System.out.println("读取完成");
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
	// 文件的复制
	public static void test03() {
		try {
			//创建通道
			//StandardOpenOption是枚举里面显示的是文件打开方式
			FileChannel inChannel = FileChannel.open(Paths.get("test1.txt"), StandardOpenOption.READ);
			FileChannel outChannel = FileChannel.open(Paths.get("test2.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
			//创建缓冲流
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			int num = 0;
			//复制
			while((num = inChannel.read(buffer)) != -1) {
				buffer.flip();
				outChannel.write(buffer);
				buffer.clear();//让指针重新回到0
			}
			
			inChannel.close();
			outChannel.close();
			System.out.println("复制完成");
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
	// 内存映射读取文件
	public static void test04() {
		try {
			//创建通道
			FileChannel inChannel = new FileInputStream("test1.txt").getChannel();
			FileChannel outChannel = new FileOutputStream("test3.txt").getChannel();
			
			//使用内存映射缓冲区
			/*
			 *只读:任何试图修改导致缓冲区会造成ReadOnlyBufferException(MapMode.READ_ONLY);
			 *读/写:对导致缓冲区的变化最终会传递到文件:他们可能会或可能不会有映射相同文件的其他程序可见(MapMode.READ_WRITE)
			 *私人:对导致缓冲区的更改不会传播到文件不会有映射同一文件的其他程序可见;相反,他们会导致缓冲区的修改部分 私有副本被创建(MapMode.PRIVATE) 
			 */
			//第一个参数是操作的模式是只读 第二个参数是读取文件的起始位置 第三个参数是终止位置
			//如果文件的大小超过2G,一般建议建立多个映射
			MappedByteBuffer mappedByteBuffer = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
			outChannel.write(mappedByteBuffer);
			
			inChannel.close();
			outChannel.close();
			System.out.println("读写完成");
			System.out.println(inChannel.getClass().toString());
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
}

Files、Path

代码1

package _Files_Path;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/*
 * NIO.2
 * Java7对原有NIO进行了重大改进,改进主要包括如下两个方面的内容
 * 1.提供了全面的文件IO和文件系统访问支持
 * 2.基于异步Channel的IO
 * Path、Paths和Files
 * 
 * 之前学习中学习过File类来访问文件系统,但是File类的功能比较有限,NIO.2为了弥补这种不足,
 * 引入了一个Path接口还提供了Files和Paths两个工具类,其中Files分装了包含大量静态方法来操作文件,
 * Paths则包含了返回Path的静态工厂方法
 */
public class demo01 {
    public static void main(String[] args) throws IOException {
    	 //Path就是用来替代File
	    //构建Path对象的两种方式
	    //传一个路径
	    Path path1 = Paths.get("D:\\123");
	    //第一个参数是盘符 ,第二个参数是可变参数 下面有多少文件路径就写多少
	    Path path2 = Paths.get("D:\\", "123","456.txt");
	    //Path是结合Files工具类使用的
	    //创建目录
	    Files.createDirectories(path1);
	    //判断文件是否存在
	    if(!Files.exists(path2)) {
	    	//创建文件
	    	Files.createFile(path2);
	    }
	    //复制文件
	    //第一个参数原文件路径, 第二个参数目标文件路径
//	  Files.copy(new FileInputStream(new File("D:\\123\\456.txt")), Paths.get("D:\\", "123","222.txt"));
//	   Files.copy(path2, new FileOutputStream(new File("D:\\123\\789.txt")));
//	   Files.copy(path2, Paths.get("D:\\", "123","111.txt")); 
	   //一次读取文件中所有的行
	    List<String> readAllLines = Files.readAllLines(Paths.get("src/com/qiangfeng/test/Demo1.java"));
        for (String str : readAllLines) {
			System.out.println("haha:"+str);
		}
        //将集合中的内容写入到文件中
        Files.write(Paths.get("D:\\", "123","Demo.java"), readAllLines);
        /*
        static BufferedReader newBufferedReader(Path path) 
		打开一个文件进行读取,返回一个 BufferedReader以有效方式从文件中读取文本。  
		static BufferedReader newBufferedReader(Path path, Charset cs) 
		打开一个文件进行读取,返回一个 BufferedReader可以用来有效方式从文件中读取文本。  
		static BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOption... options) 
		打开或创建一个文件写入,返回一个 BufferedWriter,可以有效的方式将文件写入文本。  
		static BufferedWriter newBufferedWriter(Path path, OpenOption... options) 
		打开或创建一个文件写入,返回一个 BufferedWriter能够以有效的方式的文件写入文本。  
 		
 		直接创建缓冲流对象 可以执行 字符集 和访问权限
         */
	}
}

FileVisitor

代码1

package _FileVisitor;

import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * FileVisitor参数代表的是一个文件访问器
 * walkFileTree()方法会自动遍历start路径下的所有文件和子目录,
 * 遍历文件和子目录都会触发FileVisitor中相应的方法
 * FileVisitResult postVisitDirectory(T dir, IOException exc)
 * 访问子目录之后会触发这个方法
 
 * FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
 * 访问子目录之前会触发这个方法
 
 * FileVisitResult visitFile(T file, BasicFileAttributes attrs)
 * 访问file文件时触发该方法
 
 * FileVisitResult visitFileFailed(T file, IOException exc)
 * 访问file文件失败时触发该方法
 
 * 返回FileVisitResult是一个枚举
 * CONTINUE 代表继续访问的后续行为
 * SKIP_SIBLINGS 代表继续访问的后续行为,但不访问该文件后目录的兄弟文件或目录
 * SKIP_SUBTREE 代表继续访问的后续行为,但不访问该文件或目录的子目录树
 * TERMINATE 代表终止访问的后续行为
 * 
 * 实际开发中没有必要4个方法都要重写,可以通过FileVisitor的子类SimpleFileVisitor(适配器)来创建自己的文件访问器,选择性的重写方法
 *      
 */

public class _FileVisitor_01 {
	public static void main(String args[]) {
		test01();
	}
	// 使用FileVisitor遍历文件和目录
	public static void test01() {
		try {
			Files.walkFileTree(Paths.get("C:\\Users\\Administrator\\Desktop\\Month01\\day11\\test"), new SimpleFileVisitor<Path>() {
				//访问文件时触发该方法
				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException{
					System.out.println("正在访问" + file + "文件");
					if(file.endsWith("1.jpg")) {//文件全称
						System.out.println("图片文件:" + file);
						//return FileVisitResult.TERMINATE;//终止 返回
					}
					return FileVisitResult.CONTINUE;
				}
				//开始访问目录时触发新的方法
				public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
					System.out.println("正在访问" + dir + "路径");
					return FileVisitResult.CONTINUE;
				}
			});
			
		}
		catch(IOException e) {
			e.printStackTrace();
		}
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值