Skip to content

文件

路径

  • Path路径表示文件、目录的路径,可以在不同操作系统上工作

  • 从String或URI对象创建路径

  • Path p = Paths.get(xx)
  • JDK11之后Path.of(xx)

  • 使用String设置多级路径

  • Paths.get("C:", "path", "to", "nowhere", "NoFile.txt")

  • 方法

    p.isAbsolute();//是否为绝对路径
    p.getFileName();//获取文件名称
    p.getParent();//获取上级路径
    p.getRoot();//获取最顶层路径(如 c:/)
    p.toRealPath();//获取绝对路径(取决于操作系统环境)
    p.normalize();//规范路径
    URI u = p.toUri();
    Path puri = Paths.get(u);
    

  • 切割

    for(int i = 0; i < p.getNameCount(); i++)
          System.out.println(p.getName(i));
    

  • 也可以直接使用for-in循环遍历

  • 注意对路径使用startsWith、endsWith要求是完整一项,如xx.java

  • 遍历的内容不包含根路径

  • 添加/删除路径

  • relativize(Path other)relativize 方法用于构建两个路径之间的相对路径。如果你有两个路径 AB,调用 A.relativize(B) 将返回一个路径,它从 A 导航到 B 的相对路径。它假设两个路径有一个共同的根,且不会在结果中包含根路径部分。
  • resolve(Path other)resolve 方法用于将一个路径附加到另一个路径的末尾。如果你有两个路径 AB,调用 A.resolve(B) 会创建一个合并了两个路径的新 Path 对象,如果 B 是绝对路径,则直接返回 B

Files工具类

say("Exists", Files.exists(p));
say("Directory", Files.isDirectory(p));
say("Executable", Files.isExecutable(p));
say("Readable", Files.isReadable(p));
say("RegularFile", Files.isRegularFile(p));
say("Writable", Files.isWritable(p));
say("notExists", Files.notExists(p));
say("Hidden", Files.isHidden(p));
say("size", Files.size(p));
say("FileStore", Files.getFileStore(p));
say("LastModified: ", Files.getLastModifiedTime(p));
say("Owner", Files.getOwner(p));
say("ContentType", Files.probeContentType(p));
say("SymbolicLink", Files.isSymbolicLink(p));
  • 遍历目录Files.walkFileTree(Path, SimpleFileVisitor<Path>)
  • 需要创建并传入一个(匿名类)SimpleFileVisitor\

    • preVisitDirectory:在访问目录之前调用。
    • visitFile:在访问文件时调用。
    • visitFileFailed:在文件访问失败时调用。
    • postVisitDirectory:在访问目录之后调用。
  • 示例:删除文件夹

    public static void rmdir(Path dir)
      throws IOException {
        Files.walkFileTree(dir,
          new SimpleFileVisitor <Path>() {
          @Override public FileVisitResult
          visitFile(Path file, BasicFileAttributes attrs)
          throws IOException {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
          }
          //文件夹内的文件都被删除了,可以删除目录了
          @Override public FileVisitResult
          postVisitDirectory(Path dir, IOException exc)
          throws IOException {
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
          }
        });
      }
    

  • 创建

    Path newFilePath = Paths.get("newfile.txt");
    Files.createFile(newFilePath);
    //如果文件已存在,抛 FileAlreadyExistsException
    
    Path newDirPath = Paths.get("newdir");
    Files.createDirectory(newDirPath);
    
    //创建多级目录
    Path dirsPath = Paths.get("newdir/subdir");
    Files.createDirectories(dirsPath);
    
    //删除文件或目录
    Path pathToDelete = Paths.get("fileOrDirToDelete");
    Files.delete(pathToDelete);
    //删除目录时,目录必须是空的,否则会抛出 DirectoryNotEmptyException
    

  • Files.walk提供更简单的遍历方式

  • 返回Stream<Path>对象
    Path start = Paths.get("/some/path");
    try (Stream <Path> stream = Files.walk(start, 3)) { // 遍历深度为 3
        stream.forEach(System.out:: println); // 打印每个文件和目录的路径
    }
    
//删除 txt 文件
static Path test = Paths.get("test");
  static void delTxtFiles() {
    try {
      Files.walk(test)
        .filter(f ->
          f.toString().endsWith(".txt"))
        .forEach(f -> {
          try {
            System.out.println("deleting " + f);
            Files.delete(f);
          } catch(IOException e) {
            throw new RuntimeException(e);
          }
        });
    } catch(IOException e) {
      throw new RuntimeException(e);
    }
  }

文件系统

  • 获取文件系统对象FileSystem fsys = FileSystems.getDefault();
  • 也可以通过path、uri等获取

  • 监听Path(文件目录的变化)

  • 注意只会检测目标目录下的变化(不含子目录)

    try {
        WatchService watcher =
            FileSystems.getDefault().newWatchService();
        dir.register(watcher, ENTRY_DELETE);
        Executors.newSingleThreadExecutor().submit(() -> {
            try {
                WatchKey key = watcher.take();
                for(WatchEvent evt : key.pollEvents()) {
                    System.out.println(
                        "evt.context(): " + evt.context() +
                        "\nevt.count(): " + evt.count() +
                        "\nevt.kind(): " + evt.kind());
                    System.exit(0);
                }
            } catch(InterruptedException e) {
                return;
            }
        });
    } catch(IOException e) {
        throw new RuntimeException(e);
    }
    

  • 查找文件

  • 使用PathMatcher
        //创建匹配模式,**/表示所有子目录,*.表示任意文件名称
        PathMatcher matcher = FileSystems.getDefault()
            .getPathMatcher(" glob:**/*.{tmp, txt}");
        Files.walk(test)//从特定目录遍历所有路径
            .filter(matcher:: matches)//匹配路径
            .forEach(System.out:: println);
    
    PathMatcher matcher2 = FileSystems.getDefault()
          .getPathMatcher(" glob:*.tmp ");
    Files.walk(test) // 只匹配文件名
          .filter(Files:: isRegularFile)
          .map(Path:: getFileName)//将路径映射为文件名,下面才能正常进行匹配
          .filter(matcher2:: matches)
          .forEach(System.out:: println);

读写文件

  • 读取整个文件
  • Files.readAllLines(Path)
  • 会返回一个List<String>(行划分)
  • 可以直接创建一个流.stream()便于操作
  • 是一次性将整个文件读取到内存,可能存在性能问题

  • 逐行读取文件

  • 将文件变成由行组成的stream
  • 逐行读取,性能更好
  • Files.lines(Path).skip...

  • 写入文件

  • 可以将实现了Iterable接口的对象写入文件
  • Files.write(Path,comtent);