Java面向对象系列[v1.0.0][NIO.2]

本文介绍Java7后NIO.2提供的全面文件IO和文件系统访问支持,涵盖Path、Files、WatchService等核心API,以及如何遍历目录、监控文件变化和访问文件属性。

NIO.2的文件IO和文件系统

Java7之后提供了全面的文件IO和文件系统访问支持,并且还支持异步的Channel

Path、Paths和Files核心API

NIO.2引入了一个Path接口,Path接口代表一个平台无关的平台路径,此外NIO.2还提供了Files和Paths两个工具类,其中Files包含了大量静态的工具类方法来操作文件,Paths则包含了两个返回Path的静态工厂方法

import java.io.*;
import java.net.*;
import java.nio.file.*;

public class PathTest
{
	public static void main(String[] args)
		throws Exception
	{
		// 以当前路径来创建Path对象
		Path path = Paths.get(".");
		System.out.println("path里包含的路径数量:"
			+ path.getNameCount());
		System.out.println("path的根路径:" + path.getRoot());
		// 获取path对应的绝对路径。
		Path absolutePath = path.toAbsolutePath();
		System.out.println(absolutePath);
		// 获取绝对路径的根路径
		System.out.println("absolutePath的根路径:"
			+ absolutePath.getRoot());
		// 获取绝对路径所包含的路径数量
		System.out.println("absolutePath里包含的路径数量:"
			+ absolutePath.getNameCount());
		System.out.println(absolutePath.getName(3));
		// 以多个String来构建Path对象
		Path path2 = Paths.get("g:", "publish", "codes");
		System.out.println(path2);
	}
}
import java.nio.file.*;
import java.nio.charset.*;
import java.io.*;
import java.util.*;

public class FilesTest
{
	public static void main(String[] args)
		throws Exception
	{
		// 复制文件
		Files.copy(Paths.get("FilesTest.java"),
			new FileOutputStream("a.txt"));
		// 判断FilesTest.java文件是否为隐藏文件
		System.out.println("FilesTest.java是否为隐藏文件:"
			+ Files.isHidden(Paths.get("FilesTest.java")));
		// 一次性读取FilesTest.java文件的所有行
		List<String> lines = Files.readAllLines(Paths
			.get("FilesTest.java"), Charset.forName("gbk"));
		System.out.println(lines);
		// 判断指定文件的大小
		System.out.println("FilesTest.java的大小为:"
			+ Files.size(Paths.get("FilesTest.java")));
		List<String> poem = new ArrayList<>();
		poem.add("水晶潭底银鱼跃");
		poem.add("清徐风中碧竿横");
		// 直接将多个字符串内容写入指定文件中
		Files.write(Paths.get("pome.txt"), poem,
			Charset.forName("gbk"));
		// 使用Java 8新增的Stream API列出当前目录下所有文件和子目录
		Files.list(Paths.get(".")).forEach(path -> System.out.println(path));
		// 使用Java 8新增的Stream API读取文件内容
		Files.lines(Paths.get("FilesTest.java"), Charset.forName("gbk"))
			.forEach(line -> System.out.println(line));
		FileStore cStore = Files.getFileStore(Paths.get("C:"));
		// 判断C盘的总空间,可用空间
		System.out.println("C:共有空间:" + cStore.getTotalSpace());
		System.out.println("C:可用空间:" + cStore.getUsableSpace());
	}
}

FileVisitor遍历文件和目录

Files类提供了如下两个方法来遍历文件和子目录:

  • walkFileTree(Path start, FileVisitor<? super Path> visitor): 遍历start路径下的所有文件和子目录
  • walkFileTree(Path start, Set< FileVisitOption > options, int maxDepth, FileVisitor<? super Path>visitor): 该方法跟上一个类似,但最多遍历maxDepth深度的文件

两个方法都需要FileVisitor参数,FileVisitor代表一个文件访问器,walkFileTree()方法会自动遍历start路径下的所有文件和子目录,遍历文件和子目录都会触发FileVisitor中相应的方法

FileVisitor中定义了如下4个方法:

  • 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文件失败时候触发该方法

这4个方法都返回一个FileVisitResult对象,它是一个枚举类,代表访问了之后的后续行为(FileVisitResult):

  • CONTINUE: 代表“继续访问”的后续行为
  • SKIP_SIBLINGS:代表“继续访问”的后续行为。。。。。。
  • SKIP_SUBTREE:代表“继续访问”的后续行为。。。。。。
  • TERMINATE:代表“中止访问”的后续行为。。。。。。

实际编程时,可以通过继承SimpleFileVisitor(FileVisitor的实现类)来实现自己的文件访问器

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;

public class FileVisitorTest
{
	public static void main(String[] args)
		throws Exception
	{
		// 遍历g:\publish\codes\15目录下的所有文件和子目录
		Files.walkFileTree(Paths.get("g:", "publish", "codes", "15"),
			new SimpleFileVisitor<Path>()
		{
			// 访问文件时候触发该方法
			@Override
			public FileVisitResult visitFile(Path file,
				BasicFileAttributes attrs) throws IOException
			{
				System.out.println("正在访问" + file + "文件");
				// 找到了FileInputStreamTest.java文件
				if (file.endsWith("FileInputStreamTest.java"))
				{
					System.out.println("--已经找到目标文件--");
					return FileVisitResult.TERMINATE;
				}
				return FileVisitResult.CONTINUE;
			}
			// 开始访问目录时触发该方法
			@Override
			public FileVisitResult preVisitDirectory(Path dir,
				BasicFileAttributes attrs) throws IOException
			{
				System.out.println("正在访问:" + dir + " 路径");
				return FileVisitResult.CONTINUE;
			}
		});
	}
}

WatchService监控文件变化

之前的实现方式是,启动一个后台线程监控文件,每隔一段时间去遍历一下指定目录的文件,如果发现结果不一样,则判定文件发生了变化,NIO.2的Path类提供了如下方法来监听文件系统的变化

  • register(WatchService watcher, WatchEvent.Kind<?>… events):用watcher监听该path代表的目录下的文件变化,events参数指定要监听哪些类型的事件,在这个方法中,WatchService代表一个文件系统监听服务,它负责监听path代表的目录下的文件变化,一旦使用register()方法完成注册后,接下来就可以调用WatchService的如下三个方法来获取被监听目录的文件变化事件:
    • WatchKey poll():获取下一个WatchKey,如果没有WatchKey发生就立即返回null
    • WatchKey poll(long timeout, TimeUnit unit):尝试等待timeout时间去获取下一个WatchKey
    • WatchKey take(): 获取下一个WatchKey,如果没有WatchKey发生就一直等待

如果程序需要一直监控,则应该选择使用take()方法,如果只需要监控指定时间则应该使用poll()方法

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;

public class WatchServiceTest
{
	public static void main(String[] args)
		throws Exception
	{
		// 获取文件系统的WatchService对象
		WatchService watchService = FileSystems.getDefault()
			.newWatchService();
		// 为C:盘根路径注册监听
		Paths.get("C:/").register(watchService,
			StandardWatchEventKinds.ENTRY_CREATE,
			StandardWatchEventKinds.ENTRY_MODIFY,
			StandardWatchEventKinds.ENTRY_DELETE);
		while (true)
		{
			// 获取下一个文件改动事件
			WatchKey key = watchService.take();    // ①
			for (WatchEvent<?> event : key.pollEvents())
			{
				System.out.println(event.context() +" 文件发生了 "
					+ event.kind()+ "事件!");
			}
			// 重设WatchKey
			boolean valid = key.reset();
			// 如果重设失败,退出监听
			if (!valid)
			{
				break;
			}
		}
	}
}

访问文件属性

NIO.2在java.nio.file.attribute包下提供了大量的工具类,通过这些工具类可以很简单的读写文件属性,工具类大致分为两大类:

  • XxxAttribute View:代表某种文件属性的视图
  • XxxAttributes: 代表某种文件属性的集合,程序一般通过XxxAttributeView对象来获取XxxAttributes

在这些工具类中,FileAttributeView是其他XxxAttributeView的父接口:

  • AclFileAttributeView:通过AclFileAttributeView,开发者可以为特定文件设置ACL(AccessControlList)及文件所有者属性,它的getAcl()方法返回List< AclEntry >对象,该返回值代表了该文件的权限集,通过setAcl(List)方法可以修改该文件的ACL
  • BasicFileAttributeView:它可以获取或修改文件的基本属性,包括文件的最后修改时间,最后访问时间,创建时间,大小,是否为目录,是否为符号链接等,它的readAttributes()方法返回一个BasicFileAttributes对象,对文件夹基本属性的修改是通过BasicFileAttributes对象完成的
  • DosFileAttributeView:它主要用于获取或修改文件DOS相关属性,例如文件是否只读,是否隐藏,是否为系统文件,是否是存档文件等,它的readAttributes()方法返回一个DosFileAttributes对象,对这些属性的修改其实是由DosFileAttributes对象来完成
  • FileOwnerAttributeView:它主要用于获取或修改文件的所有者,它的getOwner()方法返回一个UserPrincipal对象来代表文件所有者,也可以调用setOwner(UserPrincipal owner)方法来改变文件所有者
  • PosixFileAttributeView:它主要用于获取或修改POSIX(Portable Operatiing System Interface of INIX)属性,它的readAttributes()方法返回一个PosixFileAttributes对象,该对象可用于获取或修改文件的所有者、组所有者、访问权限信息也就是chmod干的事,这个View只在Unix、Linux等系统上有用
  • UserDefinedFileAttributeView:用于设置自定义属性
import java.io.*;
import java.util.*;
import java.nio.file.*;
import java.nio.*;
import java.nio.charset.*;
import java.nio.file.attribute.*;

public class AttributeViewTest
{
	public static void main(String[] args)
		throws Exception
	{
		// 获取将要操作的文件
		Path testPath = Paths.get("AttributeViewTest.java");
		// 获取访问基本属性的BasicFileAttributeView
		BasicFileAttributeView basicView = Files.getFileAttributeView(
			testPath, BasicFileAttributeView.class);
		// 获取访问基本属性的BasicFileAttributes
		BasicFileAttributes basicAttribs = basicView.readAttributes();
		// 访问文件的基本属性
		System.out.println("创建时间:" + new Date(basicAttribs
			.creationTime().toMillis()));
		System.out.println("最后访问时间:" + new Date(basicAttribs
			.lastAccessTime().toMillis()));
		System.out.println("最后修改时间:" + new Date(basicAttribs
			.lastModifiedTime().toMillis()));
		System.out.println("文件大小:" + basicAttribs.size());
		// 获取访问文件属主信息的FileOwnerAttributeView
		FileOwnerAttributeView ownerView = Files.getFileAttributeView(
			testPath, FileOwnerAttributeView.class);
		// 获取该文件所属的用户
		System.out.println(ownerView.getOwner());
		// 获取系统中guest对应的用户
		UserPrincipal user = FileSystems.getDefault()
			.getUserPrincipalLookupService()
			.lookupPrincipalByName("guest");
		// 修改用户
		ownerView.setOwner(user);
		// 获取访问自定义属性的FileOwnerAttributeView
		UserDefinedFileAttributeView userView = Files.getFileAttributeView(
			testPath, UserDefinedFileAttributeView.class);
		List<String> attrNames = userView.list();
		// 遍历所有的自定义属性
		for (var name : attrNames)
		{
			ByteBuffer buf = ByteBuffer.allocate(userView.size(name));
			userView.read(name, buf);
			buf.flip();
			String value = Charset.defaultCharset().decode(buf).toString();
			System.out.println(name + "--->" + value);
		}
		// 添加一个自定义属性
		userView.write("发行者", Charset.defaultCharset()
			.encode("一块大洋"));
		// 获取访问DOS属性的DosFileAttributeView
		DosFileAttributeView dosView = Files.getFileAttributeView(testPath,
			DosFileAttributeView.class);
		// 将文件设置隐藏、只读
		dosView.setHidden(true);
		dosView.setReadOnly(true);
	}
}
**高校专业实习管理平台设计与实现** 本设计项目旨在构建一个服务于高等院校专业实习环节的综合性管理平台。该系统采用当前主流的Web开发架构,基于Python编程语言,结合Django后端框架与Vue.js前端框架进行开发,实现了前后端逻辑的分离。数据存储层选用广泛应用的MySQL关系型数据库,确保了系统的稳定性和数据处理的效率。 平台设计了多角色协同工作的管理模型,具体包括系统管理员、院系负责人、指导教师、实习单位对接人以及参与实习的学生。各角色依据权限访问不同的功能模块,共同构成完整的实习管理流程。核心功能模块涵盖:基础信息管理(如院系、专业、人员信息)、实习过程管理(包括实习公告发布、实习内容规划、实习申请与安排)、双向反馈机制(单位评价与学生反馈)、实习支持与保障、以及贯穿始终的成绩评定与综合成绩管理。 在技术实现层面,后端服务依托Django框架的高效与安全性构建业务逻辑;前端界面则利用Vue.js的组件化特性与LayUI的样式库,致力于提供清晰、友好的用户交互体验。数据库设计充分考虑了实习管理业务的实体关系与数据一致性要求,并保留了未来功能扩展的灵活性。 整个系统遵循规范的软件开发流程,从需求分析、系统设计、编码实现到测试验证,均进行了多轮迭代与优化,力求在功能完备性、系统性能及用户使用体验方面达到较高标准。 **核心术语**:实习管理平台;Django框架;MySQL数据库;Vue.js前端;Python语言。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Davieyang.D.Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值