java流与文件——操作文件

【0】README

0.1) 本文描述转自 core java volume 2, 旨在理解 java流与文件——操作文件 的相关知识;
0.2) for source code, please visit https://github.com/pacosonTang/core-java-volume/blob/master/coreJavaAdvanced/chapter1/FileAndPathTest.java)


【1】Path

1.1)Path: 表示的是一个目录名序列, 其后还可以跟一个文件名;路径中的第一个部件可以是跟部件, 例如 / 或 C:/ , 而有序访问的根部件,取决于文件系统;(干货——Path类定义)

  • 1.1.1)以根目录开始的是绝对路径,否则就是相对路径;如,
    Path absolute = Paths.get(“/home”, “cay”);
    Path relative = Paths.get(“myprog”, “cay”);
  • 1.1.2) 静态的 Paths.get 方法: 接受一个或多个字符串, 并将它们用默认文件系统的路径分隔符连接起来;
  • 1.1.3)get方法: 可以获取包含多个部件构成的单个字符串, 如, 可以像下面这样从配置文件中读取路径:
    String baseDir = props.getProperty(“base.dir”);
    Path basePath = Paths.get(baseDir);

java流与文件——操作文件_第1张图片

Attention)

  • A1)路径不必对应着某个实际存在的文件, 他仅仅只是一个抽象的名字序列;
  • A2)当你想要创建文件时, 首先要创建一个路径,然后才调用方法去创建对应的文件;

1.2)组合或解析路径是司空见惯的操作,调用 p.resolve(q) 将按照下列规则返回一个路径: (干货——p后面跟着q)

  • 1.2.1)如果 q 是绝对路径, 则结果就是q;
  • 1.2.2)否则,根据文件系统的规则, 将p 后面跟着q 作为结果;
  • 1.2.3) resolve 方法有一种快捷方式,它接收一个字符串而不是路径:
    Path workPath = basePath.resolve(“work”);

  • 1.2.4)还有一个 方法: resolveSibling
    它通过解析指定路径的父路径产生其兄弟路径, 例如, 如果workPath 是 /opt/myapp/work, 那么下面的调用
    Path tempPath = workPath.resolveSibling(“temp”) 将创建 /opt/myapp/temp; (干货——创建兄弟路径)

  • 1.2.5)resolve的对立面是 relative: 即调用 p.relativeze(r) 将产生路径q, 对q进行解锁产生r;
  • 1.2.6)normalize 方法:移除所有冗余的 . 和 .. 部件(或者文件系统认为冗余的所有部件);
    如规范化 /home/cay/../fred/./ myprog 将产生 /home/fred/myprog

java流与文件——操作文件_第2张图片

  • 1.2.7)toAbsolutePath 方法: 将产生给定路径的绝对路径, 该绝对路径从根部件开始;
  • 1.2.8) Path类有许多方法用来将路径断开以及和其它路径进行组合。如:
    Path p = Paths.get(“/home”, “myprog.properties”);
    Path parent = p.getParent();
    Path file = p.getFilename();
    Path root = p.getRoot();

  • Attention) 你可能需要与遗留系统的API 交互, 它们使用的是 File 类而不是 Path 类。 Path类有一个toFile 方法, 而 File 类也有一个 toPath 方法;

【2】读写文件

2.1)Files 类可以使得普通文件操作变得快捷;

  • 2.1.1)用下面的方式很容易的读取文件的所有内容:
    byte[] bytes = Files.readAllBytes(path);
  • 2.1.2)如果想将文件当做字符串输入, 则:
    String content = enw String(bytes, charset);
  • 2.1.3)如果希望 将文件当做行序列输入, 则:
    List lines = Files.readAllLines(path, charset);
  • 2.1.4)相反地, 如果希望写出一个字符串到文件中, 则:
    Files.write(path, content.getBytes(charset));

java流与文件——操作文件_第3张图片

  • 2.1.5)向指定文件追加内容,则:
    Files.write(path, content.getBytes(charset), StandardOpoenOption.APPEND);
  • 2.1.6)还可以用下面的语句将一行集合写出到文件中:
    Files.write(path, lines);

java流与文件——操作文件_第4张图片

  • 2.1.7) 如果要处理的文件长度过大, 或者是二进制文件, 那么还是应该使用所熟悉的流或者读入器/ 写出器;
    InputStream is = Files.newInputStream(path);
    OutputStream os = Files.newOutputStream(path);
    Reader reader = Files.newBufferedReader(path, charset);
    Writer writer = Files.newBufferedWriter(path, charset);

  • 2.1.8)总结: 这些便捷方法可以将你从处理 FileInputStream, FileInputStream, BufferedReader 和 BufferedWriter 的繁复操作中解脱出来;


【3】复制、移动和删除文件

3.1)复制文件: Files.copy(fromPath, toPath);
3.2)移动文件 (复制并删除源文件): Files.move(frompath, topath);

  • 3.2.1)如果目标路径已经存在,那么复制或移动将失败;
  • 3.2.2)如果想要覆盖已有的目标路径, 可以使用 REPLACE_EXISTING 选项;
  • 3.2.3)如果想要复制文件的属性, 可以使用 COPY_ATTRIBUTES ;
  • 3.2.4)也可以同时使用者两个选项:
    Files.copy(fromPath, toPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
  • 3.2.5)可以将移动操作定义为 原子性的(要么全部成功, 要么就不成功)
    Files.move(fromPath, toPath, StandardCopyOption.ATOMIC_MOVE);
  • 3.2.6)最后删除文件,调用:
    Files.delete(path);
  • 3.2.7)如果要删除的文件不存在, delete 方法就会抛出异常;使用 deleteIfExists 不会抛出异常,
    boolean deleted = Files.deleteIfExists(path); 该方法 deleteIfExists 还可以用来移除空目录;

java流与文件——操作文件_第5张图片


【4】 创建文件和目录

4.1)创建目录: Files.createDirectory(path);
4.2)创建中间目录: Files.createDirectories(path); (迭代创建目录)

  • 4.2.1)创建空文件: Files.createFile(path)
  • 4.2.2)有些便捷方法用来在给定位置或系统指定位置创建临时文件或 临时目录:
    Path newPath = FIles.createTempFile(dir, prefix, suffix);
    Path newPath = FIles.createTempFile( prefix, suffix);
    Path newPath = FIles.createTempFile(dir, prefix);
    Path newPath = FIles.createTempFile(prefix);
  • 其中,dir 是一个Paht对象,prefix 和 suffix 是可以为 null 的字符串;例如,调用 Files.createTempFile(null, “.txt”) 可能返回一个像 /tmp/2345646464646464.txt这样的路径;

java流与文件——操作文件_第6张图片


【5】 获取文件信息

5.1)下面的静态方法都将返回一个boolean值, 表示检查路径的某个属性的结果:
exists + isHidden + isReadable + isWritable + isExecutable + isRegularFile + isDirectory + isSymbolicLink
5.2)size 方法将返回文件的字节数:
long size = Files.size(path);
5.3)getOwner: 将文件的所有者作为 java.nio.file.attribute.UserPrincipal 的一个实例返回;
5.4)所有的文件系统都会报告一个基本属性集, 它们被封装在 BasicFileAttributes 接口中, 这些属性与上述信息有部分重叠。基本文件属性包括:

  • 5.4.1)创建文件, 最后一次访问以及最后一次修改时间;
  • 5.4.2)文件时常规文件, 目录还是符号链接, 或者都不是;
  • 5.4.3)文件大小;
  • 5.4.4)文件主键, 这是某种类的对象, 具体所属类与文件系统相关, 有可能是文件的唯一标识符,也有可能不是;
  • 5.4.5)要获取这些属性,调用
    BasicFileAttributes attributes = files.readAttributes(path, BasicFileAttributes.class);

5.5) 如果你了解到用户的文件系统兼容 POSIX, 可以获取一个 PosiXFileAttributes 实例:
PosiXFileAttributes attributes = files.readAttributes(path, PosiXFileAttributes.class);
然后从中找到组拥有者, 拥有者,组,以及访问权限;

java流与文件——操作文件_第7张图片


【6】 迭代目录中的文件

6.1)problem+solution

  • 6.1.1)problem: 旧File 类有一个方法,用来获取由一个目录的所有文件构成的数组, 当目录包含大量的文件时,方法性能非常低;
  • 6.1.2)solution: File类设计了一个方法, 产生一个 Iterable 对象, 如:
    try(DirectoryStream entries = Files.newDirectoryStream(dir))
    {
    for(Path entry : entries)
    process entries
    }
  • 6.1.3)try 语句块用来确保目录流可以被正确关闭。访问目录中的项并没有具体的顺序, 可以用 glob 模式来过滤:(干货——带资源的try语句块)
    try(DirectoryStream entries = Files.newDirectoryStream(dir, “*.java”));

java流与文件——操作文件_第8张图片

  • Warning)如果使用 Windows 的 glob 语法, 则必须对反斜杠转移两次:一次为 glob 语法转义, 一次为java 字符串转义:Files.newDirectoryStream(dir, “C:\\”)

java流与文件——操作文件_第9张图片

6.2)如果想要访问某个目录的子孙成员, 转而调用 walkFileTree 方法, 并向其传递一个 FileVisitor 类型的对象, 这个对象会得到下面通知:

  • 6.2.1)在遇到一个文件或目录时: FileVisitResult visitFile(T path, BasicFileAttributes attrs)
  • 6.2.2) 在一个目录被处理前: FileVisitResult preVisitFile(T dir, IOException ex)
  • 6.2.3) 在一个目录被处理后: FileVisitResult postVisitFile(T dir, IOException ex)
  • 6.2.4) 在试图访问文件或目录时发生错误, 例如没有权限打开目录: FileVisitResult visitFileFailed(path, IOException)

6.3) 对上述每种情况, 都可以指定是否希望执行下面的操作:

  • 6.3.1)继续访问下一个文件: FileVisitResult.CONTINUE;
  • 6.3.2)继续访问,但不在访问这个目录下的任何项了: FileVisitResult.SKIP_SUBTREE;
  • 6.3.3)继续访问, 但是不在访问这个文件的兄弟文了: FileVisitResult.SKIP_SIBLINES;
  • 6.3.4)终止访问: FileVisitResult.TRIMINATE ;

6.4) 当有任何方法抛出异常时, 就会终止访问, 而这个异常会从 walkFileTree 方法中抛出;

  • Attention) FileVisitor 接口是泛化类型, 但是你也太可能会使用 除开 FileVisit 之外的东西; walkFileTree 方法可以接收 FileVisitor

【7】 ZIP 文件系统

7.1)建立一个文件系统, 包含 ZIP 文档中的所有文件;
FileSystem fs = FileSystems.newFIleSystem(Paths.get(zipname), null);

  • 7.1.1)如果知道文件名,从ZIP 文档中复制出这个文件就变得很容易:
    Files.copy(fs.getPath(sourceName), targetPath);
  • 7.1.2)要列出ZIP 文档中的所有文件, 可以遍历文件树:
FileSystem fs = FileSystems.newFIleSystem(Paths.get(zipname), null)
Files.walkFileTree(fs,.getPath("/"), new SimpleFileVisitor()
    {
        public FileVisitResult visitFile(Path file , BasicFIleAttributes attrs)
        {
            println(file);
            return FileVisitResult.CONTINUE;
        }
    }
)

java流与文件——操作文件_第10张图片

你可能感兴趣的:(java流与文件——操作文件)