• Java NIO教程 文件系统


    在NIO.2的文件系统中,Path是一切操作的基础。Path准确来说,代表着文件系统中的位置。可以代表一个目录(也就是通常所说的文件夹),也可以代表一个文件。

    在新文件系统中,还有一个不得不说的就是Files。它是一个工具类,但是这个工具类跟打了鸡血一样,强大到不可思议。以前需要写繁重代码或者需要调用第三方类库才能完成的功能,现在只需一行。

    下面的代码展示了Path的最基本操作-获取一个Path;并且通过我们得到的Path和强大的工具类Files来创建一个文件或目录

    Path dir0 = Paths.get("c:\\test");// 创建一个Path路径;Paths是工具类,用于产生Path
    Files.createDirectory(dir0);// 创建单级目录;若已经存在 则抛出异常
    Path dir1 = Paths.get("c:\\test\\Hello.java");
    Files.createFile(dir1);// 创建文件;若目录没有 则抛出异常
    Path dir2 = Paths.get("c:\\test\\Hello\\World");
    Files.createDirectories(dir2);// 创建多级目录;若已经存在 不抛出异常
    

    展示完最基础的创建功能后,再展示一点Path的高级功能——遍历目录

    遍历目录有两种方式,一种是通过DirectoryStream类来遍历单层目录,另一种就是通过实现FileVisitor接口来递归的遍历目录

    重点强调一下这两者的区别。DirectoryStream只能遍历给定的目录下的文件或目录,如果在给定的目录下还有子目录,那么DirectoryStream不会再向下遍历子目录中的内容。而用实现FileVisitor接口的方式,则在给定的目录下若还有子目录,它会接着遍历子目录中的内容(类似于深度优先搜索)

    上代码 首先给出的是DirectoryStream的方式

    Path dir3 = Paths.get("c:\\test");
    // 1.DirectoryStream可以理解成对于Path的Iterable,返回在dir3中符合第二个参数形式的Path集合
    // 2.下面用到了一种try-with-resources的写法,该写法是在java1.7中引入的语法糖(极力推荐大家用该写法,因为它可以帮助你正确的关闭资源)
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir3,
    		"*.java")) {
    	for (Path entry : stream) {
    		System.out.println(entry.getFileName());
    	}
    }
    

    再强调一下Files.newDirectoryStream的第二个参数。这种形式是glob表达式,如*.java代表的就是所有以".java"结尾的字符串

    下面再说一下,实现FileVisitor接口的方式。这里得用到Files的一个静态方法
    Files.walkFileTree(Path start,FileVisitor<? super Path> visitor)
    第一眼就感觉好复杂,而且一看walkFileTree的二个参数就不是善茬,要实现它就得实现下面的4个方法

    • FileVisitResult postVisitDirectory(T dir, IOException exc)
    • FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
    • FileVisitResult visitFile(T file, BasicFileAttributes attrs)
    • FileVisitResult visitFileFailed(T file, IOException exc)

    但好在java1.7已经提供了一个默认实现类SimpleFileVisitor,这样你就可以只用重写你需要的方法了,下面的例子是打印一个目录下所有文件的名称(文件夹的名称不打印)

    Path dir3 = Paths.get("c:\\test");
    Files.walkFileTree(dir3, new SimpleFileVisitor<Path>() {
    	@Override
    	public FileVisitResult visitFile(Path file,
    			BasicFileAttributes attrs) throws IOException {
    		System.out.println(file.getFileName());
    		return FileVisitResult.CONTINUE;
    	}
    });
    

    两段困难的代码看完了,咱们再来的简单的。

    文件的创建、删除、复制、移动、重命名等操作,都是我们平时常用的操作。以前想写的话,真得下点功夫或者直接找个第三方类库。但是现在时代不同了,有了Files一切如丝般顺滑。看看Files的文档吧,那里有许多你梦遗所求的方法。这里展示几个常用的。

    先来一段删除文件或目录的

    Path dir4 = Paths.get("c:\\test\\del");
    Files.delete(dir4);// 删除文件或文件夹;删除文件夹时,若文件夹中还有文件或文件夹则抛出异常
    Files.deleteIfExists(dir4);// 如果存在该文件或文件夹则删除
    

    删除很简单吧,下面让我们来看看复制

    复制要考虑的情况就有点多了,复制我们主要用到的方法是
    Files.copy(Path source,Path target,CopyOption... options)
    前两个参数分别为原位置和目的位置,第三个参数为复制选项。复制选项的意思,说白了就是复制时发生了各种情况时,该如何处理。CopyOption其实也应该是让你写的,但是java中内置了三种方式供你选择,它们分别是:
    StandardCopyOption.REPLACE_EXISTING:如果目的路径有同名文件则替换
    StandardCopyOption.ATOMIC_MOVE:若失败则回滚
    StandardCopyOption.COPY_ATTRIBUTES:把源文件的文件属性一同复制给新文件(readAttributes等方法可以读取文件属性)

    给你个例子

    Path source = Paths.get("c:\\test\\Hello.java");
    Path target = Paths.get("c:\\test\\Hello\\World\\Hello.java");
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    

    再就说说文件的移动,基本上与复制同理,主要用到的方法是
    Files.move(Path source,Path target,CopyOption... options)
    同样,也需要复制选项,其实给文件重命名用的也是这招,下面的例子就展示了这点

    Path source = Paths.get("c:\\test\\Hello\\World\\Hello.java");
    Path target = Paths.get("c:\\test\\Hello\\World\\He.java");
    Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
    

    下面要介绍的就是我最喜欢的内容了,给你们看两个方法
    List<String> Files.readAllLines(Path path)
    Files.write(Path path,Iterable<? extends CharSequence> lines,OpenOption... options)
    是不是一目了然。对这就是文件的按行读和按行写,用起来真的特别方便。在java1.7之前,我在guava中看见过这些方法,有时候用guava的io其实根本不是为了它的source和sink,而就是为了这几个方法。这两个方法的出现,反映了java的一种新态度,那就是纳谏、虚心。优秀的命名、方便的工具类,这都是以前java官方中所欠缺的,无论是新的Time包还是lamda表达式或是Coin项目,都是向社区学习、吸收优秀的社区资源,都是将开发者的梦想变为现实、方便开发者。
    不好意思扯远了。那就直接上代码了

    Path source = Paths.get("c:\\test\\Hello\\World\\Ab.java");
    Path target = Paths.get("c:\\test\\Hello\\World\\He.java");
    		
    //以防乱码最好设置一下文件的编码格式,在StandardCharsets中有很多种内置编码格式
    List<String> list = Files.readAllLines(source, StandardCharsets.UTF_8);
    for (String s : list) {
    	System.out.println(s);
    }
    //在StandardOpenOption中有很多种内置文件打开方式可供选择
    Files.write(target, list, StandardCharsets.UTF_8,StandardOpenOption.WRITE);
    

    整个NIO.2中的新文件系统的主要内容,也就基本这么多(文件属性这块没太说,想学的自己找找资料吧)最后咱们来的略显高端的就是文件系统的监测;主要用到的类是java.nio.file.WatchService,该类在注册后,一直监控文件或目录的变化,若有相应的变化发生,就返回一个事件。这在很多地方都是有用的,而且这个类性能不错

    try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
    	Path dir = Paths.get("c:\\test");
    	WatchKey key = dir.register(watcher,
    			StandardWatchEventKinds.ENTRY_DELETE);
    	for (;;) {
    		key = watcher.take();
    		for (WatchEvent<?> event : key.pollEvents()) {
    			System.out.println(event.kind());
    		}
    		boolean valid = key.reset();
    		if (!valid) {
    			break;
    		}
    	}
    }
    

    关于NIO.2中的新文件系统就聊这么多,有什么问题欢迎讨论,若有什么错误,望不吝赐教(赶紧告诉我,我好改,改晚了耽误其他人)

  • 相关阅读:
    重写、隐藏基类方法(new, override)
    Java FileHandler
    JMS example
    DB Locker
    计算与所有线段都重合的线段数目
    [转载] linux内存 问题
    oracle rownum & rowid mark a good tool
    java Wget Download
    java new way to implement singleton, use enum
    HttpPut Multipart and handle https request.
  • 原文地址:https://www.cnblogs.com/ironPhoenix/p/4197394.html
Copyright © 2020-2023  润新知