文档

Java™ 教程-Java Tutorials 中文版
管理元数据(文件和文件存储属性)
Trail: Essential Classes
Lesson: Basic I/O
Section: File I/O (Featuring NIO.2)

管理元数据(文件和文件存储属性)

metadata (元数据) 的定义是“关于其他数据的数据”。使用文件系统,数据包含在其文件和目录中,元数据跟踪有关每个对象的信息:它是常规文件,目录还是链接?它的大小,创建日期,上次修改日期,文件所有者,组所有者和访问权限是什么?

文件系统的元数据通常称为其 file attributes (文件属性)Files 类包括可用于获取文件的单个属性或设置属性的方法。

方法 注释
size(Path) 以字节为单位返回指定文件的大小。
isDirectory(Path, LinkOption) 如果指定的 Path 找到的文件是目录,则返回 true。
isRegularFile(Path, LinkOption...) 如果指定的 Path 找到的文件是常规文件,则返回 true。
isSymbolicLink(Path) 如果指定的 Path 找到的文件是符号链接,则返回 true。
isHidden(Path) 如果指定的 Path 找到的文件是系统认为隐藏的文件,则返回 true。
getLastModifiedTime(Path, LinkOption...)
setLastModifiedTime(Path, FileTime)
返回或设置指定文件的上次修改时间。
getOwner(Path, LinkOption...)
setOwner(Path, UserPrincipal)
返回或设置文件的所有者。
getPosixFilePermissions(Path, LinkOption...)
setPosixFilePermissions(Path, Set<PosixFilePermission>)
返回或设置文件的 POSIX 文件权限。
getAttribute(Path, String, LinkOption...)
setAttribute(Path, String, Object, LinkOption...)
返回或设置文件属性的值。

如果程序在同一时间需要多个文件属性,则使用获取单个属性的方法可能效率低下。重复访问文件系统以获取单个属性可能会对性能产生负面影响。因此,Files 类提供了两个 readAttributes 方法,用于在一次批量操作中获取文件的属性。

方法 注释
readAttributes(Path, String, LinkOption...) 将文件的属性读取为批量操作。String 参数标识要读取的属性。
readAttributes(Path, Class<A>, LinkOption...) 将文件的属性读取为批量操作。Class<A> 参数是请求的属性类型,该方法返回该类的对象。

在显示 readAttributes 方法的示例之前,应该提到不同的文件系统对于应该跟踪哪些属性有不同的概念。因此,相关文件属性被组合在一起成为视图。view 映射到特定的文件系统实现,例如 POSIX 或 DOS,或者映射到常用功能,例如文件所有权。

支持的视图如下:

特定文件系统实现可能仅支持基本文件属性视图,或者它可能支持其中几个文件属性视图。文件系统实现可能支持此 API 中未包含的其他属性视图。

在大多数情况下,你不必直接处理任何 FileAttributeView 接口。(如果确实需要直接使用 FileAttributeView,可以通过 getFileAttributeView(Path, Class<V>, LinkOption...) 方法访问它。)

readAttributes 方法使用泛型,可用于读取任何文件属性视图的属性。本页其余部分中的示例使用 readAttributes 方法。

本节的其余部分包括以下主题:

基本文件属性

如前所述,要读取文件的基本属性,可以使用 Files.readAttributes 方法之一,该方法在一个批量操作中读取所有基本属性。这比单独访问文件系统以读取每个单独的属性要有效得多。varargs 参数目前支持 LinkOption 枚举,NOFOLLOW_LINKS。如果不希望遵循符号链接,请使用此选项。


关于时间戳: 基本属性集包括三个时间戳:creationTimelastModifiedTimelastAccessTime。在特定实现中可能不支持任何这些时间戳,在这种情况下,相应的访问器方法返回特定于实现的值。支持时,时间戳将作为 FileTime 对象返回。

以下代码段读取并打印给定文件的基本文件属性,并使用 BasicFileAttributes 类中的方法。

Path file = ...;
BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class);

System.out.println("creationTime: " + attr.creationTime());
System.out.println("lastAccessTime: " + attr.lastAccessTime());
System.out.println("lastModifiedTime: " + attr.lastModifiedTime());

System.out.println("isDirectory: " + attr.isDirectory());
System.out.println("isOther: " + attr.isOther());
System.out.println("isRegularFile: " + attr.isRegularFile());
System.out.println("isSymbolicLink: " + attr.isSymbolicLink());
System.out.println("size: " + attr.size());

除了此示例中显示的访问器方法之外,还有一个 fileKey 方法,该方法返回唯一标识文件的对象,如果没有可用的文件密钥则返回 null

设置时间戳

以下代码段设置上次修改时间(以毫秒为单位):

Path file = ...;
BasicFileAttributes attr =
    Files.readAttributes(file, BasicFileAttributes.class);
long currentTime = System.currentTimeMillis();
FileTime ft = FileTime.fromMillis(currentTime);
Files.setLastModifiedTime(file, ft);
}

DOS 文件属性

除 DOS 之外的文件系统也支持 DOS 文件属性,例如 Samba。以下代码段使用 DosFileAttributes 类的方法。

Path file = ...;
try {
    DosFileAttributes attr =
        Files.readAttributes(file, DosFileAttributes.class);
    System.out.println("isReadOnly is " + attr.isReadOnly());
    System.out.println("isHidden is " + attr.isHidden());
    System.out.println("isArchive is " + attr.isArchive());
    System.out.println("isSystem is " + attr.isSystem());
} catch (UnsupportedOperationException x) {
    System.err.println("DOS file" +
        " attributes not supported:" + x);
}

但是,你可以使用 setAttribute(Path, String, Object, LinkOption...) 方法设置 DOS 属性,如下所示:

Path file = ...;
Files.setAttribute(file, "dos:hidden", true);

POSIX 文件权限

POSIX 是适用于 UNIX 的可移植操作系统接口(Portable Operating System Interface)的首字母缩写,是一组 IEEE 和 ISO 标准,旨在确保不同版本的 UNIX 之间的互操作性。如果程序符合这些 POSIX 标准,则应该可以轻松移植到其他符合 POSIX 标准的操作系统。

除文件所有者和组所有者外,POSIX 还支持九种文件权限:文件所有者,同一组成员和“其他人”的读取,写入和执行权限。

以下代码段读取给定文件的 POSIX 文件属性并将其打印到标准输出。该代码使用 PosixFileAttributes 类中的方法。

Path file = ...;
PosixFileAttributes attr =
    Files.readAttributes(file, PosixFileAttributes.class);
System.out.format("%s %s %s%n",
    attr.owner().getName(),
    attr.group().getName(),
    PosixFilePermissions.toString(attr.permissions()));

PosixFilePermissions 助手类提供了几种有用的方法,如下所示:

以下代码段从一个文件中读取属性并创建一个新文件,将原始文件中的属性分配给新文件:

Path sourceFile = ...;
Path newFile = ...;
PosixFileAttributes attrs =
    Files.readAttributes(sourceFile, PosixFileAttributes.class);
FileAttribute<Set<PosixFilePermission>> attr =
    PosixFilePermissions.asFileAttribute(attrs.permissions());
Files.createFile(file, attr);

asFileAttribute 方法将权限包装为 FileAttribute。然后,代码尝试使用这些权限创建新文件。请注意,umask 也适用,因此新文件可能比请求的权限更安全。

要将文件的权限设置为表示为硬编码字符串的值,可以使用以下代码:

Path file = ...;
Set<PosixFilePermission> perms =
    PosixFilePermissions.fromString("rw-------");
FileAttribute<Set<PosixFilePermission>> attr =
    PosixFilePermissions.asFileAttribute(perms);
Files.setPosixFilePermissions(file, perms);

Chmod 示例以类似于 chmod 实用程序的方式递归更改文件的权限。

设置文件或组所有者

要将名称转换为可以存储为文件所有者或组所有者的对象,可以使用 UserPrincipalLookupService 服务。此服务将名称或组名称查找为字符串,并返回表示该字符串的 UserPrincipal 对象。你可以使用 FileSystem.getUserPrincipalLookupService 方法获取默认文件系统的用户主体查找服务。

以下代码段显示了如何使用 setOwner 方法设置文件所有者:

Path file = ...;
UserPrincipal owner = file.GetFileSystem().getUserPrincipalLookupService()
        .lookupPrincipalByName("sally");
Files.setOwner(file, owner);

Files 类中没有用于设置组所有者的特殊方法。但是,直接执行此操作的安全方法是通过 POSIX 文件属性视图,如下所示:

Path file = ...;
GroupPrincipal group =
    file.getFileSystem().getUserPrincipalLookupService()
        .lookupPrincipalByGroupName("green");
Files.getFileAttributeView(file, PosixFileAttributeView.class)
     .setGroup(group);

用户定义的文件属性

如果文件系统实现支持的文件属性不足以满足你的需要,则可以使用 UserDefinedAttributeView 创建和跟踪自己的文件属性。

一些实现将此概念映射到 NTFS 备用数据流等功能以及文件系统(如 ext3 和 ZFS)上的继承属性。大多数实现都对值的大小施加了限制,例如,ext3 将大小限制为 4 千字节。

通过使用以下代码片段,可以将文件的 MIME 类型存储为用户定义的属性:

Path file = ...;
UserDefinedFileAttributeView view = Files
    .getFileAttributeView(file, UserDefinedFileAttributeView.class);
view.write("user.mimetype",
           Charset.defaultCharset().encode("text/html");

要阅读 MIME 类型属性,你可以使用以下代码段:

Path file = ...;
UserDefinedFileAttributeView view = Files
.getFileAttributeView(file,UserDefinedFileAttributeView.class);
String name = "user.mimetype";
ByteBuffer buf = ByteBuffer.allocate(view.size(name));
view.read(name, buf);
buf.flip();
String value = Charset.defaultCharset().decode(buf).toString();

Xdd 示例显示了如何获取,设置和删除用户定义的属性。


注意: 在 Linux 中,你可能必须启用继承属性才能使用户定义的属性起作用。如果在尝试访问用户定义的属性视图时收到 UnsupportedOperationException,则需要重新装入文件系统。以下命令使用 ext3 文件系统的继承属性重新安装根分区。如果此命令不适合你的 Linux 风格,请参阅文档。
$ sudo mount -o remount,user_xattr /

如果要使更改成为永久更改,请在 /etc/fstab 中添加一个条目。


文件存储属性

你可以使用 FileStore 类来了解有关文件存储的信息,例如可用空间大小。getFileStore(Path) 方法获取指定文件的文件存储。

以下代码段打印特定文件所在的文件存储的空间使用情况:

Path file = ...;
FileStore store = Files.getFileStore(file);

long total = store.getTotalSpace() / 1024;
long used = (store.getTotalSpace() -
             store.getUnallocatedSpace()) / 1024;
long avail = store.getUsableSpace() / 1024;

DiskUsage 示例使用此 API 打印默认文件系统中所有存储的磁盘空间信息。此示例使用 FileSystem 类中的 getFileStores 方法来获取文件系统的所有文件存储。


Previous page: Moving a File or Directory
Next page: Reading, Writing, and Creating Files