管理文件属性
文件和文件存储属性
文件系统的元数据通常称为其文件属性。 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()
方法的示例之前,应该提到不同的文件系统对应该跟踪哪些属性有不同的概念。为此,相关的文件属性被分组到视图中。视图映射到特定文件系统实现(例如 POSIX 或 DOS)或常见功能(例如文件所有权)。
支持的视图如下
BasicFileAttributeView
– 提供对所有文件系统实现都必须支持的基本属性的视图。DosFileAttributeView
– 使用支持 DOS 属性的文件系统上支持的标准四位扩展基本属性视图。PosixFileAttributeView
– 使用支持 POSIX 标准系列(例如 UNIX)的文件系统上支持的属性扩展基本属性视图。这些属性包括文件所有者、组所有者以及九个相关的访问权限。FileOwnerAttributeView
– 支持任何支持文件所有者概念的文件系统实现。AclFileAttributeView
– 支持读取或更新文件的访问控制列表 (ACL)。支持 NFSv4 ACL 模型。任何具有到 NFSv4 模型的明确映射的 ACL 模型(例如 Windows ACL 模型)也可能得到支持。UserDefinedFileAttributeView
– 支持用户定义的元数据。此视图可以映射到系统支持的任何扩展机制。例如,在 Solaris 操作系统中,可以使用此视图存储文件的 MIME 类型。
特定文件系统实现可能只支持基本文件属性视图,或者可能支持这些文件属性视图中的几个。文件系统实现可能支持此 API 中未包含的其他属性视图。
在大多数情况下,您不必直接处理任何 FileAttributeView
接口。(如果您确实需要直接使用 FileAttributeView
,您可以通过 getFileAttributeView(Path, Class<V>, LinkOption...)
方法访问它。)
readAttributes()
方法使用泛型,可用于读取任何文件属性视图的属性。本页其余部分中的示例使用 readAttributes()
方法。
基本文件属性
如前所述,要读取文件的基本属性,可以使用 Files.readAttributes()
方法之一,该方法在一个批量操作中读取所有基本属性。这比单独访问文件系统以读取每个单独属性要高效得多。varargs 参数当前支持 LinkOption
枚举,NOFOLLOW_LINKS
。当您不希望跟踪符号链接时,请使用此选项。
关于时间戳的一句话:基本属性集包括三个时间戳:
creationTime
、lastModifiedTime
和lastAccessTime
。在特定实现中可能不支持这些时间戳中的任何一个,在这种情况下,相应的访问器方法将返回一个特定于实现的值。如果支持,则时间戳将作为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,是一组 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
辅助类提供以下几种有用的方法
- 在前面的代码片段中使用的
toString()
方法将文件权限转换为字符串(例如,rw-r--r--
)。 fromString()
方法接受表示文件权限的字符串,并构造一个Set
文件权限。asFileAttribute()
方法接受一个Set
文件权限,并构造一个可以传递给Files.createFile()
或Files.createDirectory()
方法的文件属性。
以下代码片段从一个文件读取属性,并创建一个新文件,将原始文件的属性分配给新文件
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);
设置文件或组所有者
要将名称转换为可以存储为文件所有者或组所有者的对象,可以使用 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();
注意:在 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;
确定 MIME 类型
要确定文件的 MIME 类型,您可能会发现 probeContentType(Path)
方法很有用。例如
try {
String type = Files.probeContentType(filename);
if (type == null) {
System.err.format("'%s' has an" + " unknown filetype.%n", filename);
} else if (!type.equals("text/plain") {
System.err.format("'%s' is not" + " a plain text file.%n", filename);
continue;
}
} catch (IOException x) {
System.err.println(x);
}
请注意,如果无法确定内容类型,此方法将返回 null。
此方法的实现高度依赖于平台,并非万无一失。内容类型由平台的默认文件类型检测器确定。例如,如果检测器根据 .class
扩展名确定文件的类型为 application/x-java
,则可能会被欺骗。
如果默认类型不足以满足您的需求,您可以提供自定义的 FileTypeDetector
。
上次更新: 2023 年 1 月 25 日