Java NIO Files

来源:互联网 发布:达特康票务网络系统 编辑:程序博客网 时间:2024/06/03 16:12

最近在看并发网的Java NIO系列,发现这篇文章还没有翻译,于是抽空翻译了一下~
相关内容:并发网Java NIO 系列教程、Java NIO Files原文链接

Java NIO Files类 (java.nio.file.Files) 提供了几种操作几种文件系统中的文件的方法。这个Java NIO Files教程将涵盖最常用的一些方法。 Files类包含很多方法,如果你需要一个这里没有描述到的方法请自行查看JavaDoc。Files类可能正好有一个对应的方法。

Files.exists()

Files.exists()方法用于检查指定路径Path在文件系统中是否存在。

可以创建文件系统中不存在的Path实例。例如,如果你打算创建一个新目录,则首先应创建相应的Path实例,然后再创建该目录。

由于Path实例可能(也可能不)指向一个已经存在的实例,因此你可以使用Files.exists()来检查(如果你需要的话)。

下面是一个Files.exists()示例:

Path path = Paths.get("data/logging.properties");boolean pathExists = Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS});

此示例首先创建一个Path实例指向我们想要检查是否存在的路径。然后,该示例调用Files.exists()方法并将Path实例作为第一个参数。

注意Files.exists()的第二个参数。此参数是一个可以影响Files.exists()如何确定路径是否存在的选项数组。在上面的示例中,数组包含LinkOption.NOFOLLOW_LINKS,这意味着Files.exists()方法不应该跟随文件系统中的符号链接来确定路径是否存在。

Files.createDirectory()

Files.createDirectory()方法从一个Path实例中创建一个新的目录,下面是一个Files.createDirectory()示例:

Path path = Paths.get("data/subdir");try {    Path newDir = Files.createDirectory(path);} catch(FileAlreadyExistsException e){    // the directory already exists.} catch (IOException e) {    //something else went wrong    e.printStackTrace();}

第一行创建一个代表要创建的目录的Path实例。在try-catch块中Files.createDirectory()方法将Path实例作为参数传入进行调用。如果目录创建成功,则返回一个指向新路径的Path实例。

如果目录已经存在,一个java.nio.file.FileAlreadyExistsException异常会被抛出。如果发生其他错误,IOException异常可能会被抛出。例如,如果新目录所需的父目录不存在,则可能会抛出IOException异常。父目录是要在其中创建新目录的目录,因此它是新目录的父目录。

Files.copy()

Files.copy()方法将文件从一个路径复制到另一个路径。下面是一个Java NIO Files.copy()的示例:

Path sourcePath = Paths.get("data/logging.properties");Path destinationPath = Paths.get("data/logging-copy.properties");try {    Files.copy(sourcePath, destinationPath);} catch(FileAlreadyExistsException e) {    //destination file already exists} catch (IOException e) {    //something else went wrong    e.printStackTrace();}

首先,该示例创建一个源和目标Path实例。然后调用Files.copy()并将两个Path实例作为参数传递。这将导致源路径引用的文件被复制到目标路径引用的文件中。

如果目标路径已经存在,一个java.nio.file.FileAlreadyExistsException异常将被抛出。如果发生其他错误,将抛出一个IOException异常。例如,如果文件复制到的目录不存在,则会抛出IOException异常。

覆盖现有文件

可以使用Files.copy()强制覆盖现有文件。下面是一个展示如何使用Files.copy()覆盖现有文件的示例:

Path sourcePath = Paths.get("data/logging.properties");Path destinationPath = Paths.get("data/logging-copy.properties");try {    Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);} catch(FileAlreadyExistsException e) {    //destination file already exists} catch (IOException e) {    //something else went wrong    e.printStackTrace();}

注意Files.copy()方法的第三个参数。如果目标文件已存在,此参数将指示copy()方法覆盖现有文件。

Files.move()

Java NIO Files类还包含了一个将文件从一个路径移动到另一个路径的方法。移动文件与重命名相同,除了移动文件可以将其移动到不同的目录,并在同一操作中更改其名称。是的,java.io.File类可以使用它的renameTo()方法来实现,但是现在java.nio.file.Files类中也提供了文件移动功能。

下面是一个Files.move()的示例:

Path sourcePath = Paths.get("data/logging-copy.properties");Path destinationPath = Paths.get("data/subdir/logging-moved.properties");try {    Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);} catch (IOException e) {    //moving file failed.    e.printStackTrace();}

首先创建源路径和目标路径。源路径指向要移动的文件,目标路径指向应移动到的位置。然后调用Files.move()方法,这将导致文件被移动。

注意传递给Files.move()的第三个参数。此参数指示Files.move()方法覆盖目标路径上的任何现有文件。这个参数实际上是可选的。

如果移动文件失败,Files.move()方法可能会抛出IOException。例如,如果文件已经存在于目标路径,而你省略了StandardCopyOption.REPLACE_EXISTING选项,或者要移动的文件不存在等等。

Files.delete()

Files.delete()方法可以删除文件或目录。下面是一个Java Files.delete()的示例:

Path path = Paths.get("data/subdir/logging-moved.properties");try {    Files.delete(path);} catch (IOException e) {    //deleting file failed    e.printStackTrace();}

首先创建指向要删除的文件的Path实例,然后调用Files.delete()方法。如果Files.delete()因为某些原因(例如文件或目录不存在)而无法删除该文件,则抛出IOException。

Files.walkFileTree()

Files.walkFileTree()方法包含递归遍历目录树的功能。walkFileTree()方法使用Path实例和FileVisitor作为参数。Path实例指向要遍历的目录。在遍历过程中会调用FileVisitor。

在我解释遍历过程是如何工作的之前,先来看一下FileVisitor接口:

public interface FileVisitor {    public FileVisitResult preVisitDirectory(        Path dir, BasicFileAttributes attrs) throws IOException;    public FileVisitResult visitFile(        Path file, BasicFileAttributes attrs) throws IOException;    public FileVisitResult visitFileFailed(        Path file, IOException exc) throws IOException;    public FileVisitResult postVisitDirectory(        Path dir, IOException exc) throws IOException {}

你必须实现FileVisitor接口,并将实现的实例传递给walkFileTree()方法。FileVisitor实现的每一个方法将在目录遍历期间的不同时间被调用。如果你不需要使用到所有方法,可以继承SimpleFileVisitor类,该类包含FileVisitor接口所有方法的默认实现。

下面是一个walkFileTree()的示例:

Files.walkFileTree(path, new FileVisitor<Path>() {  @Override  public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {    System.out.println("pre visit dir:" + dir);    return FileVisitResult.CONTINUE;  }  @Override  public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {    System.out.println("visit file: " + file);    return FileVisitResult.CONTINUE;  }  @Override  public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {    System.out.println("visit file failed: " + file);    return FileVisitResult.CONTINUE;  }  @Override  public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {    System.out.println("post visit directory: " + dir);    return FileVisitResult.CONTINUE;  }});

FileVisitor实现中的每个方法在遍历期间的不同时间被调用:

preVisitDirectory()方法将在访问任何目录之前被调用。在访问目录之后调用postVisitDirectory()方法。

文件遍历过程中,访问每个文件都调用了visitFile()方法。它不是为目录调用,而是只针对文件。访问文件失败时调用visitFileFailed()方法。例如,如果你没有正确的权限,或者其他问题。

四个方法都会返回一个FileVisitResult枚举实例。FileVisitResult枚举包含以下四个选项:

  • CONTINUE
  • TERMINATE
  • SKIP_SIBLINGS
  • SKIP_SUBTREE

通过获取到的返回值,被调用的方法可以决定文件遍历如何继续。

CONTINUE 意味着文件遍历应该正常继续。

TERMINATE 意味着文件遍历应该终止。

SKIP_SIBLINGS 意味着文件遍历应该继续,但不要访问此文件或目录的任何相邻元素。

SKIP_SUBTREE 意味着文件遍历应该继续,但不能访问此目录中的条目。该值仅在从preVisitDirectory()返回时才具有该功能。如果从任何其他方法返回,它将被解释为CONTINUE。

搜索文件

这是一个继承SimpleFileVisitor的walkFileTree(),以查找名为README.txt的文件:

Path rootPath = Paths.get("data");String fileToFind = File.separator + "README.txt";try {  Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {    @Override    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {      String fileString = file.toAbsolutePath().toString();      //System.out.println("pathString = " + fileString);      if(fileString.endsWith(fileToFind)){        System.out.println("file found at path: " + file.toAbsolutePath());        return FileVisitResult.TERMINATE;      }      return FileVisitResult.CONTINUE;    }  });} catch(IOException e){    e.printStackTrace();}

递归删除目录

Files.walkFileTree()也可被用于删除一个带有文件和子目录的目录。Files.delete()方法只能删除空目录。通过遍历所有目录并删除每个目录中的所有文件(在visitFile()中),然后删除目录本身(在PostVisitDirectory())中),您可以删除带有子目录和文件的目录。这是一个递归目录删除的例子:

Path rootPath = Paths.get("data/to-delete");try {  Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {    @Override    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {      System.out.println("delete file: " + file.toString());      Files.delete(file);      return FileVisitResult.CONTINUE;    }    @Override    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {      Files.delete(dir);      System.out.println("delete dir: " + dir.toString());      return FileVisitResult.CONTINUE;    }  });} catch(IOException e){  e.printStackTrace();}

Files类中的附加方法

java.nio.file.Files类包含许多其他有用的功能,例如用于创建符号链接的功能,确定文件大小,设置文件权限等。有关这些方法的更多信息,请查看java.nio.file.Files类的JavaDoc。