欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java开发笔记(九十五)NIO配套的文件工具Files

程序员文章站 2022-04-09 09:34:02
NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths、路径工具Path、文件组工具Files。先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的路径字符串,输出该文件路径的路径对象Path。通过get方法获取路径对象的代码示例如下: 有了Pat ......

nio不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具paths、路径工具path、文件组工具files。先看路径组工具paths,该工具提供了静态方法get,输入某个文件的路径字符串,输出该文件路径的路径对象path。通过get方法获取路径对象的代码示例如下:

		// 根据指定的文件路径字符串获得对应的path对象
		path path = paths.get(mdirname);

 

有了path对象之后,就能调用它的各种实例方法了,常见的几个方法说明如下:
getparent:获取当前路径所在的上级目录的path对象。
resolve:拼接文件路径,在当前路径的末尾添加指定字符串,并返回新的文件路径。
startswith:判断当前路径是否以指定字符串开头。
endswith:判断当前路径是否以指定字符串结尾。
tostring:获取当前路径对应的名称字符串。
tofile:获取当前路径对应的file对象。
看上去路径组工具paths和路径工具path平淡无奇,并无什么出众之处。原来真正方便的是文件组工具files,它集成了众多实用的功能技巧,且看下列的各个方法说明:
exists:判断该路径是否存在。
isdirectory:判断该路径是否为目录。
isexecutable:判断该路径是否允许执行。
ishidden:判断该路径是否隐藏。
isreadable:判断该路径是否可读。
iswritable:判断该路径是否可写。
size:获取该路径的文件大小。如果该路径是文件,则返回文件大小;如果该路径是目录,则返回目录基本信息的大小,而非整个目录的大小。
createdirectory:如果该路径是个目录,就创建新目录。
createfile:如果该路径是个文件,就创建新文件。
delete:如果该路径是文件或者空目录,就把它删掉。如果该路径不存在或者目录非空,就扔出异常。
deleteifexists:如果该路径是文件或者空目录,就把它删掉(路径不存在也不报错)。但若目录非空,还是扔出异常。
copy:把文件从源路径复制到目标路径。
move:把文件从源路径移动到目标路径。
另外,java8又给files工具增加了以下几个方法,使之具备流式处理的能力:
readalllines:获取该文件的所有内容行,返回的是字符串清单。
lines:获取该文件的所有内容行,返回的是字符串流stream<string>。
list:获取该目录下的所有文件与目录,但不包括子目录的下级内容,返回的是路径流stream<path>。
walk:获取该目录下的所有文件与目录,且包括指定深度子目录的下级内容,返回的是路径流stream<path>。

接下来通过几个实际案例演示以上文件工具的详细用法。

一、通过path打开文件通道
之前介绍文件通道的时候,提到有两种方式可以创建文件通道,第一种方式可以调用输入输出流的getchannel方法获取通道对象,第二种方式可以调用随机文件工具的getchannel方法获取通道对象。其实还有第三种方式,就是调用filechannel工具的open方法,根据传入的path对象也能获得通道对象。不加选项参数的open方法,默认得到只读的文件通道;若要得到可写的文件通道,则需给open方法传入选项参数standardopenoption.write。下面是利用路径工具创建文件通道的代码例子:

	// 通过path打开文件通道
	private static void openchannelfrompath() {
		try {
			// 根据指定的文件路径字符串获得对应的path对象
			path path = paths.get(mfilename);
			// 创建文件通道的第三种方式:通过path打开文件的只读通道。open方法不加选项参数的话,默认是只读权限
			filechannel readchannel = filechannel.open(path, standardopenoption.read);
			readchannel.close();
			// 创建文件通道的第三种方式:通过path打开文件的写入通道。
			// open方法的第二个参数指定了文件以只读方式还是以可写方式打开
			filechannel writechannel = filechannel.open(path, standardopenoption.write);
			writechannel.close();
		} catch (exception e) {
			e.printstacktrace();
		}
	}

 

需要注意的是,通过path打开可写的文件通道有个问题:要是文件通道指向的文件路径并不存在,那么往该通道写入数据将会扔出异常,而非默认创建新文件。因而获取可写的文件通道之前必须添加检查代码,即判断指定路径是否存在,倘若该路径不存在,则要创建一个新文件。完整的检查代码如下所示:

	// 根据文件路径获取path对象。如果指定路径的文件不存在,就创建一个新文件。
	private static path getpath(string filename) {
		path path = paths.get(filename);
		if (!files.exists(path)) { // 该文件路径并不存在
			try {
				files.createfile(path); // 在该路径创建新文件
			} catch (ioexception e) {
				e.printstacktrace();
			}
		}
		return path;
	}

 

可是依稀记得,不管是从输入输出流获取文件通道,还是从随机文件工具获取文件通道,都没有手工创建新文件的步骤呀。那是因为即使指定路径的文件不存在,输出流和随机文件工具都会自动创建文件,无需程序员去手工创建。因此实际开发中若要创建文件通道,基本采取前两种方式,很少使用path工具的第三种方式。

二、遍历指定目录下(不包含子目录)的所有文件与目录
调用files工具的list方法即可实现指定目录(不包含子目录)的遍历功能,list方法返回的遍历结果为字符串流,后续即可通过流式处理做进一步的加工。比如要统计指定目录下面文件与目录数量,则先调用list方法获得字符串流对象,再调用count方法就能得到统计数目。具体的统计代码示例如下:

		// 根据指定的文件路径字符串获得对应的path对象
		path path = paths.get(mdirname);
		try {
			// 计算该目录下(不包含子目录)的所有文件与目录的总数
			long listcount = files.list(path).count();
			system.out.println("listcount="+listcount);
		} catch (exception e) {
			e.printstacktrace();
		}

  

三、遍历指定目录下(包含子目录)的所有文件与目录
倘若要求对指定目录及其子目录进行遍历操作,则可调用files工具的walk方法,该方法支持设定待遍历的子目录深度(从当前目录往下数的目录层数)。譬如要统计指定目录及五层以内子目录下面文件与目录数量,则先调用walk方法获得字符串流对象,再调用count方法就能得到统计数目。此时包含子目录的统计代码如下所示:

		try {
			// 根据指定的文件路径字符串获得对应的path对象
			path path = paths.get(mdirname);
			// 遍历该目录以及深度在五之内的子目录,计算其下所有文件与目录的总数
			long count = files.walk(path, 5).count();
			system.out.println("count="+count);
		} catch (exception e) {
			e.printstacktrace();
		}

 

walk方法与list方法同样返回的都是流对象,所以流式处理的filter、map、collect等方法统统适用,非常方便对某目录下的所有实体进行筛选操作。例如打算遍历指定目录以及深度在五之内的子目录,并返回其下所有目录的路径名称清单,利用walk方法实现的筛选代码是下面这样的:

		try {
			// 根据指定的文件路径字符串获得对应的path对象
			path path = paths.get(mdirname);
			// 遍历该目录以及深度在五之内的子目录,并返回其下所有目录的路径名称清单
			list<string> dirs = files.walk(path, 5)
					.filter(files::isdirectory) // 只挑选目录
					.map(it -> it.tostring()) // 获取目录的路径名称
					.collect(collectors.tolist()); // 返回清单格式
			system.out.println("dirs="+dirs);
		} catch (exception e) {
			e.printstacktrace();
		}

 

由此可见,流式处理在nio的文件工具中大放异彩,代码逻辑结构清晰、代码行数量也少,实为文件遍历的一员福将。
通过walk方法筛选指定目录下的某种类型文件也很方便,例如想要挑出某目录下面所有的png图片文件路径,则采取walk方法辅以流式处理的实现代码如下所示:

		try {
			// 根据指定的文件路径字符串获得对应的path对象
			path path = paths.get(mdirname);
			// 遍历该目录以及深度在五之内的子目录,并返回其下所有png文件的路径名称清单
			list<string> pngs = files.walk(path, 5)
					.filter(it -> it.tofile().isfile()) // 只挑选文件
					.filter(it -> it.endswith(".png")) // 挑出扩展名为png的文件
					.map(it -> it.tostring()) // 获取目录的路径名称
					.collect(collectors.tolist()); // 返回清单格式
			system.out.println("pngs="+pngs);
		} catch (exception e) {
			e.printstacktrace();
		}

 

以上的文件筛选代码果然清爽,一点都不拖泥带水。



更多java技术文章参见《java开发笔记(序)章节目录

上一篇: 小姑娘不错

下一篇: 党性告诉我