[NIO.2] 第二十九篇 删除、复制、移动目录和文件

删除、拷贝和移动操作是最常见的文件操作。NIO.2 提供了独立的方法来支持这些操作。它们中的大部分都来自 Files 类。

[b][size=x-large]删除文件和目录[/size][/b]

NIO.2 提供了两个方法来删除文件和目录,分别是 Files.delete() 和 Files.deleteIfExits()。这两个方法都接受一个 Path 类型的参数用于指定删除对象。不同的是,Files.delete() 的返回值是 void,而 Files.deleteIfExits() 的返回值是 boolean。

Files.delete() 方法试图删除传入的 Path 对象,如果删除失败,则有可能抛出下面的异常:NoSuchFileException (如果传入的 Path 文件/目录不存在),DirectoryNotEmptyException (如果传入的 Path 对象是一个目录,并且目录不为空),IOException (如果发生 I/O 异常), SecurityException (如果没有权限进行删除操作)。

下面的代码段将删除 C:\rafaelnadal\photos\ 目录下的 rafa_1.jpg 文件(文件必须存在)。

Path path = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_1.jpg"); 

//delete the file
try {
Files.delete(path);
} catch (NoSuchFileException | DirectoryNotEmptyException | IOException |
SecurityException e) {
System.err.println(e);
}


如果使用 Files.deleteIfExists() 删除文件,文件必须存在,否则会返回 false(用于取代抛出 NoSuchFileException 异常)。这在多线程的环境下删除文件很有用,因为你可能会不希望线程中抛出异常。

下面的代码同样会删除 rafa_1.jpg 文件:

try { 
boolean success = Files.deleteIfExists(path);
System.out.println("Delete status: " + success);
} catch (DirectoryNotEmptyException | IOException | SecurityException e) {
System.err.println(e);
}


注:如果要删除目录,那么目录必须为空,否则需要先进行递归删除目录下的所有内容。

[b][size=x-large]复制文件和目录[/size][/b]

复制是 NIO.2 提供的最美妙的方法之一。NIO.2 一共提供了三个 copy() 方法来完成这个任务,并且提供了一组选项来控制复制过程。copy() 方法是用非定长参数来接受这些选项。这些选项保存在 StandardCopyOption 和 LinkOption 枚举类型中,如下所示:

[list]
[*] REPLACE_EXISTING - 如果文件已经存在,则会被替换(如果复制的是非空目录,则会抛出 FileAlreadyExistsException 异常);如果复制的是软链接,则只是复制软链接本身,而不会复制目标文件。
[*] COPY_ATTRIBUTES - 赋值文件并且连同文件属性(至少会有 lastModifiedTime 属性支持复制)。
[*] NOFOLLOW_LINKS - 不考虑软链接目标文件,只考虑软链接自身。
[/list]

如果你对枚举类型不熟,那么你可以使用下面的静态导入方式导入到你的类中:

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;


注:默认情况下,如果被复制的文件是软连接,那么复制的将会是目标文件,只有使用了 REPLACE_EXISTING 和 NOFOLLOW_LINKS 选项才会赋值软链接本身。另外,文件属性默认不会被复制。

注意:试图复制一个非空目录最终会得到一个空目录。非空目录的复制需要进行递归复制下面的子目录和文件。另外,赋值文件的操作并不是一个原子操作,因此有可能会发生 IOException 或者赋值过程被打断的情况。

[b][size=large]在两个 Path 对象之间复制[/size][/b]

NIO.2 提供了 copy() 方法进行拷贝,它接受两个 Path 对象用于指定源文件和目标文件,还有一组用于控制复制过程的参数。返回目标文件 Path。默认情况下,若目标文件已存在,复制会失败。

下面的代码将会复制 draw_template.txt 文件(文件必须存在),从 C:\rafaelnadal\grandslam\AustralianOpen 复制到 C:\rafaelnadal\grandslam\USOpen。它将替换已有文件,并且会复制文件属性,不支持软链接。

Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt"); 
Path copy_to= Paths.get("C:/rafaelnadal/grandslam/USOpen",copy_from.getFileName().toString());

try {

Files.copy(copy_from, copy_to, REPLACE_EXISTING, COPY_ATTRIBUTES, NOFOLLOW_LINKS);

} catch (IOException e) {
System.err.println(e);
}


[b][size=large]从输入流复制到文件[/size][/b]

可以调用 Files.copy() 方法从输入流复制到文件,这个方法会返回读取或写出的字节数。默认情况下,如果目标文件已经存在,则复制失败。

下面代码段将使用输入流将文件 draw_template.txt 从 C:\rafaelnadal\grandslam\AustralianOpen 复制到 C:\rafaelnadal\grandslam\Wimbledon 并替换已有文件。

Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt"); 
Path copy_to = Paths.get("C:/rafaelnadal/grandslam/Wimbledon", "draw_template.txt");

try (InputStream is = new FileInputStream(copy_from.toFile())) {

Files.copy(is, copy_to, REPLACE_EXISTING);

} catch (IOException e) {
System.err.println(e);
}


输入流可以通过另外的途径获得,例如,下面的代码将会从 URL 获取输入流,并复制到 C:\rafaelnadal\photos 目录下(使用默认选项,文件必须不存在):

Path copy_to = Paths.get("C:/rafaelnadal/photos/rafa_winner_2.jpg"); 
URI u = URI.create("https://lh6.googleusercontent.com/--
udGIidomAM/Tl8KTbYd34I/AAAAAAAAAZw/j2nH24PaZyM/s800/rafa_winner.jpg");

try (InputStream in = u.toURL().openStream()) {

Files.copy(in, copy_to);

} catch (IOException e) {
System.err.println(e);
}


[b][size=large]复制文件到输出流[/size][/b]

可以调用 Files.copy() 方法从文件复制到输出流,这个方法会返回读取或写出的字节数。

下面的代码会将文件 draw_template.txt 从 C:\rafaelnadal\grandslam\AustralianOpen 复制到 C:\rafaelnadal\grandslam\RolandGarros,复制过程使用输出流(如果目标文件存在,则会被覆盖)。

Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt"); 
Path copy_to = Paths.get("C:/rafaelnadal/grandslam/RolandGarros", "draw_template.txt");

try (OutputStream os = new FileOutputStream(copy_to.toFile())) {

Files.copy(copy_from, os);
} catch (IOException e) {
System.err.println(e);
}


[b][size=x-large]移动文件和目录[/size][/b]

可以使用 Files.move() 方法来移动文件,这个方法接受两个 Path 类型对象,分别表示源文件和目标文件。并接受一组可选的参数,用于控制移动过程。这些参数存在在 StandardCopyOption 枚举类型中:

REPLACE_EXISTING - 如果目标文件已经存在,则会被覆盖;如果操作的是软连接,那么软链接将会被替换并且指向的目标文件不变。
ATOMIC_MOVE - 保证文件移动的原子性,这将保证任何任何监控文件目录的操作都将访问到完整的文件。

默认情况下,如果目标文件已经存在,移动将会失败。当移动软链接时,移动的是软链接本身而非目标文件。

下面的代码将会移动 rafa_2.jpg 文件,从 C:\rafaelnadal 到 C:\rafaelnadal\photos,如果文件存在,则会覆盖,因为使用了 REPLACE_EXISTING 选项:

Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/rafa_2.jpg");
Path moveto = FileSystems.getDefault().getPath("C:/rafaelnadal/photos/rafa_2.jpg");

try {
Files.move(movefrom, moveto, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.err.println(e);
}


你可以使用 Path.resolve() 方法来避免文件名硬编码。下面的代码演示从源文件提取文件名并移动到目标目录下:

Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/rafa_2.jpg"); 
Path moveto_dir = FileSystems.getDefault().getPath("C:/rafaelnadal/photos");

try {
Files.move(movefrom, moveto_dir.resolve(movefrom.getFileName()),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.err.println(e);
}


[size=x-large]重命名文件[/size]

最后,演示一下如何使用 Files.move() 和 Path.resolveSibling() 方法对文件进行重命名。下面的代码将 rafa_2.jpg 重命名为 rafa_renamed_2.jpg:

Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/photos/rafa_2.jpg"); 

try {
Files.move(movefrom, movefrom.resolveSibling("rafa_2_renamed.jpg"),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.err.println(e);
}


文章来源:[url]http://www.aptusource.org/2014/04/nio-2-delete-copy-move-files/[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值