Java 7:复制和移动文件和目录

这篇文章是我关于Java 7 java.nio.file软件包的系列文章的继续,这次涵盖了文件的复制和移动以及完整的目录树。 如果您曾经对Java缺少copy和move方法感到沮丧,那么请继续阅读,以免麻烦。 涵盖范围中包括非常有用的Files.walkFileTree方法。 但是,在我们深入研究主要内容之前,需要一些背景信息。

路径对象
路径对象代表可能包含或不包含文件的目录序列。 有三种方法构造Path对象:

  1. FileSystems.getDefault()。getPath(字符串优先,字符串…更多)
  2. Paths.get(String path,String…更多),调用FileSystems.getDefault()。getPath的便捷方法
  3. 在java.io.File对象上调用toPath方法

从现在开始,在所有示例中,我们将使用Paths.get方法。 以下是创建Path对象的一些示例:

//Path string would be "/foo"
Paths.get("/foo");
//Path string "/foo/bar"
Paths.get("/foo","bar");

要操作Path对象,可以使用Path.resolve和Path.relativize方法。 这是使用Path.resolve的示例:

//This is our base path "/foo"
Path base = Paths.get("/foo");
//filePath is "/foo/bar/file.txt" while base still "/foo"
Path filePath = base.resolve("bar/file.txt");

使用Path.resolve方法会将给定的String或Path对象附加到调用Path的末尾,除非给定的String或Path表示绝对路径,否则将返回给定的路径,例如:

Path path = Paths.get("/foo");
//resolved Path string is "/usr/local"
Path resolved = path.resolve("/usr/local");

Path.relativize以相反的方式工作,返回一个新的相对路径,如果根据调用的Path解析该路径,则会得到相同的Path字符串。 这是一个例子:

// base Path string "/usr"Path base = Paths.get("/usr");// foo Path string "/usr/foo"Path foo = base.resolve("foo");// bar Path string "/usr/foo/bar"Path bar = foo.resolve("bar");// relative Path string "foo/bar"Path relative = base.relativize(bar);

Path类上另一个有用的方法是Path.getFileName,它返回此Path对象表示的最远元素的名称,该名称是实际文件或目录。 例如:

//assume filePath constructed elsewhere as "/home/user/info.txt"
//returns Path with path string "info.txt"
filePath.getFileName()//now assume dirPath constructed elsewhere as "/home/user/Downloads"
//returns Path with path string "Downloads"
dirPath.getFileName()

在下一节中,我们将研究如何将Path.resolve和Path.relativize与Files类一起使用来复制和移动文件。

文件类

Files类由使用Path对象处理文件和目录的静态方法组成。 尽管Files类中有50多种方法,但目前我们仅讨论复制和移动方法。

复制文件

要将一个文件复制到另一个文件,您可以使用(对名称有任何猜测吗?)Files.copy方法– copy(路径源,Path目标,CopyOption…选项)非常简洁并且没有匿名内部类,我们确定它是Java吗? options参数是枚举,用于指定应如何复制文件。 (实际上有2个不同的Enum类,LinkOption和StandardCopyOption,但是都实现CopyOption接口。)这是Files.copy的可用选项列表:

  1. LinkOption.NOFOLLOW_LINKS
  2. StandardCopyOption.COPY_ATTRIBUTES
  3. StandardCopyOption.REPLACE_EXISTING

还有一个StandardCopyOption.ATOMIC_MOVE枚举,但是如果指定了此选项,则抛出UsupportedOperationException。 如果未指定任何选项,则默认为在目标文件存在或为符号链接的情况下引发错误。 如果路径对象是目录,那么将在目标位置中创建一个空目录。 (请稍等!在引言中没有说我们可以复制目录的全部内容吗?答案仍然是肯定的,而且即将到来!)这是使用Path使用Path对象将文件复制到另一个文件的示例.resolve和Path.relativize方法:

Path sourcePath ...Path basePath ...Path targetPath ...Files.copy(sourcePath, targetPath.resolve(basePath.relativize(sourcePath));

移动文件

移动文件同样简单明了– move(路径源,路径目标,CopyOption…选项);

可用的StandardCopyOptions枚举是:

  1. StandardCopyOption.REPLACE_EXISTING
  2. StandardCopyOption.ATOMIC_MOVE

如果使用StandardCopyOption.COPY_ATTRIBUTES调用Files.move,则会引发UnsupportedOperationException。 可以在空目录上调用Files.move,或者如果它不需要移动目录内容,例如重新命名,则调用将成功,否则将抛出IOException(我们将在下一节中看到如何移动非空目录)。 如果目标文件已经存在,则默认为引发Exception。 如果源是符号链接,则链接本身将被移动,而不是链接的目标。 这是Files.move的示例,再次使用Path.relativize和Path.resolve方法:

Path sourcePath ...Path basePath ...Path targetPath ...Files.move(sourcePath, targetPath.resolve(basePath.relativize(sourcePath));

复制和移动目录

Files.walkFileTree是在Files类中找到的更有趣和有用的方法之一。 walkFileTree方法执行文件树的深度优先遍历。 有两个签名:

  1. walkFileTree(路径开始,设置选项,int maxDepth,FileVisitor访问者)
  2. walkFileTree(路径开始,FileVisitor访问者)

Files.walkFileTree的第二个选项使用EnumSet.noneOf(FileVisitOption.class)和Integer.MAX_VALUE调用第一个选项。 在撰写本文时,只有一个文件访问选项– FOLLOW_LINKS。 FileVisitor是一个接口,具有定义的四个方法:

  1. preVisitDirectory(T dir,BasicFileAttributes attrs)在遍历所有整数之前调用目录。
  2. visitFile(T file,BasicFileAttributes attrs)调用目录中的文件。
  3. postVisitDirectory(T dir,IOException exc)仅在遍历所有文件和子目录之后才调用。
  4. visitFileFailed(T file,IOException exc)调用了无法访问的文件

所有方法都返回四个可能的FileVisitResult枚举之一:

  1. FileVistitResult.CONTINUE
  2. FileVistitResult.SKIP_SIBLINGS(继续而不遍历目录或文件的同级)
  3. FileVistitResult.SKIP_SUBTREE(继续而不遍历目录内容)
  4. FileVistitResult.TERMINATE

为了使生活更轻松,有一个默认的FileVisitor实现,即SimpleFileVisitor(validate参数不为null并返回FileVisitResult.CONTINUE),可以将其子类化,您可以覆盖您需要使用的方法。 让我们看一个用于复制整个目录结构的基本示例。

复制目录树示例

让我们看一下扩展用于复制目录树的SimpleFileVisitor的类(为清晰起见,省略了一些详细信息):

public class CopyDirVisitor extends SimpleFileVisitor<Path> {private Path fromPath;private Path toPath;private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;....@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {Path targetPath = toPath.resolve(fromPath.relativize(dir));if(!Files.exists(targetPath)){Files.createDirectory(targetPath);}return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.copy(file, toPath.resolve(fromPath.relativize(file)), copyOption);return FileVisitResult.CONTINUE;}
}

在第9行中,将遍历源文件“ fromPath”中的每个目录,并在目标“ toPath”中创建每个目录。 在这里,我们可以看到Path对象在处理目录和文件方面的强大功能。 随着代码深入目录结构,只需分别在fromPath和toPath对象上调用relativize和resolve即可构造正确的Path对象。 我们根本不需要知道我们在目录树中的位置,因此不需要繁琐的StringBuilder操作即可创建正确的路径。 在第17行,我们看到用于将文件从源目录复制到目标目录的Files.copy方法。 接下来是删除整个目录树的简单示例。

删除目录树示例

在此示例中,SimpleFileVisitor已被子类化,用于删除目录结构:

public class DeleteDirVisitor  extends SimpleFileVisitor<Path> {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.delete(file);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {if(exc == null){Files.delete(dir);return FileVisitResult.CONTINUE;}throw exc;}
}

如您所见,删除是一个非常简单的操作。 只需删除找到的每个文件,然后在退出时删除目录即可。

将Files.walkFileTree与Google Guava结合

前两个示例虽然有用,但非常“香草”。 让我们看一下另外两个示例,它们结合了Google Gauva Function和Predicate接口,它们更具创造力。

public class FunctionVisitor extends SimpleFileVisitor<Path> {Function<Path,FileVisitResult> pathFunction;public FunctionVisitor(Function<Path, FileVisitResult> pathFunction) {this.pathFunction = pathFunction;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {return pathFunction.apply(file);}
}

在这个非常简单的示例中,我们将SimpleFileVisitor子类化,以将Function对象作为构造函数参数,并且在遍历目录结构时,将该函数应用于每个文件。

public class CopyPredicateVisitor extends SimpleFileVisitor<Path> {private Path fromPath;private Path toPath;private Predicate<Path> copyPredicate;public CopyPredicateVisitor(Path fromPath, Path toPath, Predicate<Path> copyPredicate) {this.fromPath = fromPath;this.toPath = toPath;this.copyPredicate = copyPredicate;}@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {if (copyPredicate.apply(dir)) {Path targetPath = toPath.resolve(fromPath.relativize(dir));if (!Files.exists(targetPath)) {Files.createDirectory(targetPath);}return FileVisitResult.CONTINUE;}return FileVisitResult.SKIP_SUBTREE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.copy(file, toPath.resolve(fromPath.relativize(file)));return FileVisitResult.CONTINUE;}
}

在此示例中,CopyPredicateVisitor接收一个Predicate对象,并且基于返回的布尔值,不会复制部分目录结构。 我想指出的是,前面两个示例(除了有用性之外)确实可以在本文后面的源代码中进行单元测试。

DirUtils

在到目前为止所介绍的所有内容的基础上,我无法抗拒创建实用程序类DirUtils的机会, 该类是使用以下提供以下方法的目录的抽象:

//deletes all files but leaves the directory tree in placeDirUtils.clean(Path sourcePath);//completely removes a directory treeDirUtils.delete(Path sourcePath);//replicates a directory treeDirUtils.copy(Path sourcePath, Path targetPath);//not a true move but performs a copy then a delete of a directory treeDirUtils.move(Path sourcePath, Path targetPath);//apply the function to all files visitedDirUtils.apply(Path sourcePath,Path targetPath, Function function);

虽然我不愿意说它已经可以生产了,但是写起来很有趣。

结论

这就包装了java.nio.file包提供的新的复制和移动功能。 我个人认为这非常有用,并且可以减轻使用Java中文件的痛苦。 还有更多内容,涉及符号链接,流复制方法,DirectoryStreams等,因此请务必坚持。 谢谢你的时间。 一如既往地欢迎提出意见和建议。

参考: Java 7的新增功能: JCG合作伙伴的 文件和目录的复制和移动   比尔·贝杰克(Bill Bejeck)在“ 编码随机思想”博客上。


翻译自: https://www.javacodegeeks.com/2012/02/java-7-copy-and-move-files-and.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/373332.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 五子棋项目_Java项目如何实现五子棋小游戏

Java项目如何实现五子棋小游戏发布时间&#xff1a;2020-07-21 14:53:06来源&#xff1a;亿速云阅读&#xff1a;77作者&#xff1a;小猪小编这次要给大家分享的是Java项目如何实现五子棋小游戏&#xff0c;文章内容丰富&#xff0c;感兴趣的小伙伴可以来了解一下&#xff0c;希…

Java中多线程的使用!!

简介&#xff1a; 1.要了解多线程&#xff0c;首先我们得先了解进程和线程。那么什么是进程&#xff1f;进程就是一个正在运行的程序分配内存让应用程序能够运行的叫做进程。那么什么又是线程呢&#xff1f;线程&#xff1a;在一个程序中&#xff0c;负责代码的执行&#xff0c…

java pkcs1转pkcs8_pkcs1与pkcs8格式RSA私钥互相转换

1、PKCS1私钥生成openssl genrsa -out private.key 1024private.key文件内容如下&#xff1a;-----BEGIN RSA PRIVATE KEY-----MIICXQIBAAKBgQDREk3uy4x9i4a16OYOYEp5Ir2f16lsmUHB2HjGDlxkU0ju9YApyeZlUXb191ZkxJ2vx2vKppN4gKLDy5r7JMTpwch1CNvceySX6DiM4lwTAnUEZiBYgNBNrKINEt…

嵌入式码头,Vaadin和焊接

当我开发Web应用程序时&#xff0c;我希望能够从Eclipse快速启动它们&#xff0c;而不必依赖各种重量级的tomcat或glassfish插件。 因此&#xff0c;我通常要做的只是创建一个可以直接从Eclipse运行的基于Java的简单启动器。 该启动器会在几秒钟内启动&#xff0c;因此使开发工…

创建真机调试证书(苹果开发者平台各个选项对应的含义)

创建真机调试证书&#xff08;苹果开发者平台各个选项对应的含义&#xff09; 原文地址&#xff1a;http://jingyan.baidu.com/article/ff411625b8141312e48237a7.html转载于:https://www.cnblogs.com/siasyl/p/5340593.html

gl.vertexAtteib3f P42 讲数据传给location参数指定的attribute变量

参数  location  指定将要修改的attribute变量存储位置 v0  指定填充attribute变量第一个分量的值 v1  指定填充attribute变量第二个分量的值 v2  指定填充attribute变量第三个分量的值 var VSHADER_SOURCE attribute vec4 a_Position;\n void main(){\n gl_Posit…

将Spring集成到旧版应用程序中

所有Spring开发人员喜欢做的事情之一就是将Spring塞入他们正在工作的任何应用程序中–这是我生活中的罪恶感之一&#xff1a;您看到一些代码&#xff0c;认为它是垃圾&#xff0c;因为它包含几个众所周知的反模式&#xff0c;然后想想如果这个应用程序是Spring应用程序会多么酷…

java自己实现ioc_springioc原理、springmvc项目分析、自己实现IOC

从一个面试题开始&#xff1a;你自己实现IOC容器的话&#xff0c;保存bean你会使用什么数据结构来保存呢&#xff1f;现在的很多开发人员(甚至3年以上的)不一定能回答这问题&#xff0c;为什么会这样呢&#xff1f;这个跟现在springboot现在已经高度成熟了&#xff0c;很多配置…

实现两级下拉框的联动

1.实现两级下拉框的联动。 功能&#xff1a;实现点击年级下拉框&#xff0c;加载对应科目的下拉框。 第一步&#xff1a;首先要加载年级下拉框中的数据。 01.在GradeDAL层&#xff08;数据访问层&#xff09;写一个方法&#xff0c;查询所有年级的信息。 /// <summary>//…

System.nanoTime()背后是什么?

在Java世界中&#xff0c;对System.nanoTime&#xff08;&#xff09;的理解非常好。 总有一些人说它是快速&#xff0c;可靠的&#xff0c;并且在可能的情况下&#xff0c;应该使用它代替System.currentTimemillis&#xff08;&#xff09;进行计时。 总的来说&#xff0c;他绝…

python连接SQL Server取多个结果集:Pymssql模块

基本的用法可以参考&#xff1a;python连接SQL Server&#xff1a;Pymssql模块 和上一篇文章中的代码&#xff0c;只取一个结果集不同&#xff0c;这次会一次运行2个sql语句&#xff0c;然后分别取出2个结果集&#xff0c;打印输出。 代码中有详细的注释&#xff0c;一看就明白…

状态不属于代码

Web应用程序中的“状态”是什么&#xff1f; 它就是要存储的数据&#xff08;无论目的地是什么—内存&#xff0c;数据库&#xff0c;文件系统&#xff09;。 应用程序本身不得在代码中存储任何状态。 这意味着您的类应仅包含带有无状态对象的字段。 换句话说&#xff0c;在程序…

Xen安全架构sHype/ACM策略配置图文教程

实验要求 1. 熟悉Xen虚拟化平台部署&#xff1b; 2. Xen sHype/ACM安全架构中的Simple TE和Chinese Wall策略及事实上现机制的分析与验证。 第1章 Xen环境部署 1.1 版本号选择 因为Ubuntu使用广泛。软件包易于下载。我们选择Ubuntu系统进行Xen部署…

Python 辨异 —— __init__ 与 __new__

__init__ 更多的作用是初始化属性&#xff0c;__new__ 进行的是创建对象&#xff0c;显然 __new__ 要早于 __init__ 发生。 考虑一个继承自 tuple 的类&#xff0c;显然在 __init__ 无法对其成员进行修改&#xff1b; class Edge(tuple):def __new__(cls, e1, e2):return tuple…

java弹出虚拟键盘_JS实现电脑虚拟键盘的操作

本文实例为大家分享了JS实现电脑虚拟键盘的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下需求&#xff1a;1.当输入框光标聚焦时&#xff0c;电脑虚拟键盘弹出2.在输入框输入内容时&#xff0c;键盘跟着变化具体实现代码如下&#xff1a;Html部分&#xff1a;电脑键…

Apache Mahout:入门

最近&#xff0c;我有一个有趣的问题要解决&#xff1a;如何使用自动化对不同来源的文本进行分类&#xff1f; 前一段时间&#xff0c;我读到一个有关该项目以及许多其他文本分析工作的项目– Apache Mahout 。 尽管它不是一个非常成熟的版本&#xff08;当前版本为0.4 &#x…

Javascript中最常用的55个经典技巧(转)

1. οncοntextmenu"window.event.returnValuefalse" 将彻底屏蔽鼠标右键 <table border οncοntextmenureturn(false)><td>no</table> 可用于Table 2. <body onselectstart"return false"> 取消选取、防止复制 3. οnpaste"…

向数组添加元素 java_java如何向数组里添加元素

向数组里添加一个元素怎么添加&#xff0c;这儿总结有三种方法&#xff1a;1、一般数组是不能添加元素的&#xff0c;因为他们在初始化时就已定好长度了&#xff0c;不能改变长度。但有个可以改变大小的数组为ArrayList&#xff0c;即可以定义一个ArrayList数组&#xff0c;然后…

JBoss Drools –入门

这篇文章是关于我如何掌握JBoss Drools的 。 其背后的原因是&#xff1a;SAP收购了我公司当前的规则引擎&#xff0c;而Drools是我们将寻找的另一种选择&#xff0c;只要有人掌握了概念验证的技能即可。 尽管似乎有大量的文档&#xff0c;但是我总是会通过示例来发现它是有帮助…

android使用bintray发布aar到jcenter

前言 这两天心血来潮突然想把自己的android library的aar放到jcenter里面&#xff0c;这样一来自己便可以在任何时间任何地点通过internet得到自己的library的引用了&#xff0c;况且现在android studio已经默认使用jcenter的repositories作为依赖来源&#xff0c;以前的mavenc…