Java NIO 教程(十五) Java NIO Files

原文地址

目录

Java NIO Files类(java.nio.file.Files)提供了几种操作文件系统中的文件的方法。这个Java NIO Files教程将介绍最常用的这些方法。Files类包含许多方法,所以如果您需要一个在这里没有描述的方法,那么请检查JavaDoc。Files类可能还会有一个方法来实现它。

java.nio.file.Files类与java.nio.file.Path实例一起工作,因此在处理Files类之前,您需要了解Path类。

Files.exists()

Files.exists()方法检查给定的Path在文件系统中是否存在。

可以创建在文件系统中不存在的Path实例。例如,如果您计划创建一个新目录,您首先要创建相应的Path实例,然后创建目录。

由于Path实例可能指向,也可能没有指向文件系统中存在的路径,你可以使用Files.exists()方法来确定它们是否存在(如果需要检查的话)。

这里是一个Java 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){
    // 目录已经存在
} catch (IOException e) {
    // 其他发生的异常
    e.printStackTrace();
}

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

如果该目录已经存在,则是抛出一个java.nio.file.FileAlreadyExistsException。如果出现其他错误,可能会抛出IOException。例如,如果想要的新目录的父目录不存在,则可能会抛出IOException。父目录是您想要创建新目录的目录。因此,它表示新目录的父目录。

Files.copy()

Files.copy()方法从一个路径拷贝一个文件到另外一个目录,这里是一个Java 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) {
    // 目录已经存在
} catch (IOException e) {
    // 其他发生的异常
    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) {
    // 目标文件已存在
} catch (IOException e) {
    // 其他发生的异常
    e.printStackTrace();
}

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

Files.move()

Java NIO Files还包含一个函数,用于将文件从一个路径移动到另一个路径。移动文件与重命名相同,但是移动文件既可以移动到不同的目录,也可以在相同的操作中更改它的名称。是的,java.io.File类也可以使用它的renameTo()方法来完成这个操作,但是现在已经在java.nio.file.Files中有了文件移动功能。

这里有一个Java 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) {
    //移动文件失败
    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) {
    // 删除文件失败
    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_SIBLING 跳过同级
  • SKIP_SUBTREE 跳过子级

通过返回其中一个值,调用方法可以决定如何继续执行文件。

CONTINUE继续意味着文件的执行应该像正常一样继续。

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

SKIP_SIBLINGS跳过同级意味着文件遍历应该继续,但不需要访问该文件或目录的任何同级。

SKIP_SUBTREE跳过子级意味着文件遍历应该继续,但是不需要访问这个目录中的子目录。这个值只有从preVisitDirectory()返回时才是一个函数。如果从任何其他方法返回,它将被解释为一个CONTINUE继续。

文件搜索

这里是一个用于扩展SimpleFileVisitorwalkFileTree(),以查找一个名为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();
}

文件类中的其他方法

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 原文地址 目录 Java NIO教程 Java NIO 教程(一) 概述 Java NIO 教程(二) Chann...
    步积阅读 8,745评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • Java 语言支持的类型分为两类:基本类型和引用类型。整型(byte 1, short 2, int 4, lon...
    xiaogmail阅读 1,339评论 0 10
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,327评论 0 17
  • 依窗远眺,瞭望天涯路;于斯长相守,额头已爬满了艰辛;夜凄凄,难觅黎明那一缕曦光,确见那沧桑!夕阳穿透窗棂,...
    阿荚阅读 217评论 0 16