#管理元数据(文件和文件存储属性)
# 管理元数据(文件和文件存储属性) 元数据的定义:“其他数据的数据”。使用文件系统,数据包含在其文件和目录中,元数据跟踪有关每个对象的信息:它是常规文件,目录还是链接?
它的大小,创建日期,上次修改日期,文件所有者,组所有者和访问权限是多少?
文件系统的元数据通常称为其 文件属性。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
因此,Files 该类提供了两种 readAttributes 在一个批量操作中获取文件属性的方法。
方法 说明 readAttributes(Path, String, LinkOption...) 读取文件的属性作为批量操作。该 String 参数标识要读取的属性。 readAttributes(Path, Class, LinkOption...) 读取文件的属性作为批量操作。该 Class 参数是所请求的属性的类型,该方法返回该类的对象。 在显示 readAttributes 方法的示例之前,应该提到不同的文件系统对于哪些属性应该被跟踪有不同的概念。
因此,将相关的文件属性分组到视图中。视图映射到一个特定的文件系统的实例,如 POSIX 或 DOS,或到共同的功能性,如文件所有权。
支持的视图如下:
BasicFileAttributeView - 提供所有文件系统实现所需的基本属性视图。 DosFileAttributeView - 扩展支持 DOS 属性的文件系统上支持的标准四位的基本属性视图。 PosixFileAttributeView - 扩展支持 POSIX 系列标准的文件系统(如 UNIX)上支持的属性的基本属性视图。这些属性包括文件所有者,组所有者和九个相关访问权限。 FileOwnerAttributeView - 支持支持文件所有者概念的任何文件系统实现。 AclFileAttributeView - 支持读取或更新文件的访问控制列表(ACL)。支持 NFSv4 ACL 模型。还可以支持任何具有对 NFSv4 模型的定义良好的 ACL 模型,如 Windows ACL 模型。 UserDefinedFileAttributeView - 支持用户定义的元数据。该视图可以映射到系统支持的任何扩展机制。例如,在 Solaris OS 中,您可以使用此视图来存储文件的 MIME 类型。 特定的文件系统实现可能只支持基本的文件属性视图,或者可能支持其中几个文件属性视图。文件系统实现可能支持未包含在此 API 中的其他属性视图。
在大多数情况下,您不必直接处理任何 FileAttributeView 接口。(如果您确实需要直接使用 FileAttributeView,
则可以通过该 getFileAttributeView(Path, Class
这些 readAttributes 方法使用泛型,可用于读取任何文件属性视图的属性。本页其余部分的示例使用 readAttributes 方法。
本节的其余部分涵盖以下主题:
基本文件属性 设定时间戳 DOS 文件属性 POSIX 文件权限 设置文件或组所有者 用户定义的文件属性 文件存储属性 # 基本文件属性 如前所述,要阅读文件的基本属性,您可以使用一种 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());
123456789101112除了本示例演示的访问器外,有一个 fileKey 方法返回一个表示此文件的唯一标识,如果没有则返回 null。在一部分系统上有这个 filekey.
# 设定时间戳 下面的代码片段设置最后修改时间以毫秒为单位:
Path file = ...;
BasicFileAttributes attr =
Files.readAttributes(file, BasicFileAttributes.class);
long currentTime = System.currentTimeMillis();
FileTime ft = FileTime.fromMillis(currentTime);
Files.setLastModifiedTime(file, ft);
1234567# 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);
}
123456789101112但是,您可以使用该 setAttribute(Path, String, Object, LinkOption...) 方法设置 DOS 属性 ,如下所示:
Path file = ...;
Files.setAttribute(file, "dos:hidden", true);
12# POSIX 文件权限 ! 以下示例没有经过验证,因为在 windows 下
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()));
1234567该 PosixFilePermissions 助手类提供了一些有用的方法,具体如下:
toString 在上一个代码片段中使用的方法将文件权限转换为字符串(例如,rw-r--r--)。 fromString 方法接受表示文件权限的字符串,并构造一个 Set 文件权限。 asFileAttribute 方法接受一个 Set 文件权限并构造一个可以传递给 Path.createFile 或者 Path.createDirectory 方法的文件属性。 以下代码段从一个文件中读取属性,并创建一个新文件,将属性从原始文件分配给新文件:
Path sourceFile = ...;
Path newFile = ...;
PosixFileAttributes attrs =
Files.readAttributes(sourceFile, PosixFileAttributes.class);
FileAttribute
PosixFilePermissions.asFileAttribute(attrs.permissions());
Files.createFile(file, attr);
1234567该 asFileAttribute 方法将权限包装为 FileAttribute。然后,代码尝试使用这些权限创建一个新文件。
请注意,这 umask 也适用,所以新文件可能比请求的权限更安全。
要将文件的权限设置为以硬编码字符串表示的值,可以使用以下代码:
Path file = ...;
Set
PosixFilePermissions.fromString("rw-------");
FileAttribute
PosixFilePermissions.asFileAttribute(perms);
Files.setPosixFilePermissions(file, perms);
123456这里有一个官网示例:同样我没有测试过.功能是:似于 chmod 实用程序的方式递归地更改文件的权限。
import java.nio.file.*;
import java.nio.file.attribute.*;
import static java.nio.file.attribute.PosixFilePermission.*;
import static java.nio.file.FileVisitResult.*;
import java.io.IOException;
import java.util.*;
/**
* Sample code that changes the permissions of files in a similar manner to the
* chmod(1) program.
*/
public class Chmod {
/**
* Compiles a list of one or more symbolic mode expressions that
* may be used to change a set of file permissions. This method is
* intended for use where file permissions are required to be changed in
* a manner similar to the UNIX chmod program.
*
*
The {@code exprs} parameter is a comma separated list of expressions
* where each takes the form:
*
* who operator [permissions]
*
* where who is one or more of the characters {@code 'u'}, {@code 'g'},
* {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or
* all (owner, group, and others) respectively.
*
*
operator is the character {@code '+'}, {@code '-'}, or {@code
* '='} signifying how permissions are to be changed. {@code '+'} means the
* permissions are added, {@code '-'} means the permissions are removed, and
* {@code '='} means the permissions are assigned absolutely.
*
*
permissions is a sequence of zero or more of the following:
* {@code 'r'} for read permission, {@code 'w'} for write permission, and
* {@code 'x'} for execute permission. If permissions is omitted
* when assigned absolutely, then the permissions are cleared for
* the owner, group, or others as identified by who. When omitted
* when adding or removing then the expression is ignored.
*
*
The following examples demonstrate possible values for the {@code
* exprs} parameter:
*
*
| {@code u=rw} | Sets the owner permissions to be read and write. |
| {@code ug+w} | Sets the owner write and group write permissions. |
| {@code u+w,o-rwx} | Sets the owner write, and removes the others read, others write
* and others execute permissions. |
| {@code o=} | Sets the others permission to none (others read, others write and
* others execute permissions are removed if set) |
*
* @param exprs
* List of one or more symbolic mode expressions
*
* @return A {@code Changer} that may be used to changer a set of
* file permissions
*
* @throws IllegalArgumentException
* If the value of the {@code exprs} parameter is invalid
*/
public static Changer compile(String exprs) {
// minimum is who and operator (u= for example)
if (exprs.length() < 2)
throw new IllegalArgumentException("Invalid mode");
// permissions that the changer will add or remove
final Set
final Set
// iterate over each of expression modes
for (String expr: exprs.split(",")) {
// minimum of who and operator
if (expr.length() < 2)
throw new IllegalArgumentException("Invalid mode");
int pos = 0;
// who
boolean u = false;
boolean g = false;
boolean o = false;
boolean done = false;
for (;;) {
switch (expr.charAt(pos)) {
case 'u' : u = true; break;
case 'g' : g = true; break;
case 'o' : o = true; break;
case 'a' : u = true; g = true; o = true; break;
default : done = true;
}
if (done)
break;
pos++;
}
if (!u && !g && !o)
throw new IllegalArgumentException("Invalid mode");
// get operator and permissions
char op = expr.charAt(pos++);
String mask = (expr.length() == pos) ? "" : expr.substring(pos);
// operator
boolean add = (op == '+');
boolean remove = (op == '-');
boolean assign = (op == '=');
if (!add && !remove && !assign)
throw new IllegalArgumentException("Invalid mode");
// who= means remove all
if (assign && mask.length() == 0) {
assign = false;
remove = true;
mask = "rwx";
}
// permissions
boolean r = false;
boolean w = false;
boolean x = false;
for (int i=0; i switch (mask.charAt(i)) { case 'r' : r = true; break; case 'w' : w = true; break; case 'x' : x = true; break; default: throw new IllegalArgumentException("Invalid mode"); } } // update permissions set if (add) { if (u) { if (r) toAdd.add(OWNER_READ); if (w) toAdd.add(OWNER_WRITE); if (x) toAdd.add(OWNER_EXECUTE); } if (g) { if (r) toAdd.add(GROUP_READ); if (w) toAdd.add(GROUP_WRITE); if (x) toAdd.add(GROUP_EXECUTE); } if (o) { if (r) toAdd.add(OTHERS_READ); if (w) toAdd.add(OTHERS_WRITE); if (x) toAdd.add(OTHERS_EXECUTE); } } if (remove) { if (u) { if (r) toRemove.add(OWNER_READ); if (w) toRemove.add(OWNER_WRITE); if (x) toRemove.add(OWNER_EXECUTE); } if (g) { if (r) toRemove.add(GROUP_READ); if (w) toRemove.add(GROUP_WRITE); if (x) toRemove.add(GROUP_EXECUTE); } if (o) { if (r) toRemove.add(OTHERS_READ); if (w) toRemove.add(OTHERS_WRITE); if (x) toRemove.add(OTHERS_EXECUTE); } } if (assign) { if (u) { if (r) toAdd.add(OWNER_READ); else toRemove.add(OWNER_READ); if (w) toAdd.add(OWNER_WRITE); else toRemove.add(OWNER_WRITE); if (x) toAdd.add(OWNER_EXECUTE); else toRemove.add(OWNER_EXECUTE); } if (g) { if (r) toAdd.add(GROUP_READ); else toRemove.add(GROUP_READ); if (w) toAdd.add(GROUP_WRITE); else toRemove.add(GROUP_WRITE); if (x) toAdd.add(GROUP_EXECUTE); else toRemove.add(GROUP_EXECUTE); } if (o) { if (r) toAdd.add(OTHERS_READ); else toRemove.add(OTHERS_READ); if (w) toAdd.add(OTHERS_WRITE); else toRemove.add(OTHERS_WRITE); if (x) toAdd.add(OTHERS_EXECUTE); else toRemove.add(OTHERS_EXECUTE); } } } // return changer return new Changer() { @Override public Set perms.addAll(toAdd); perms.removeAll(toRemove); return perms; } }; } /** * A task that changes a set of {@link PosixFilePermission} elements. */ public interface Changer { /** * Applies the changes to the given set of permissions. * * @param perms * The set of permissions to change * * @return The {@code perms} parameter */ Set } /** * Changes the permissions of the file using the given Changer. */ static void chmod(Path file, Changer changer) { try { Set Files.setPosixFilePermissions(file, changer.change(perms)); } catch (IOException x) { System.err.println(x); } } /** * Changes the permission of each file and directory visited */ static class TreeVisitor implements FileVisitor private final Changer changer; TreeVisitor(Changer changer) { this.changer = changer; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { chmod(dir, changer); return CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { chmod(file, changer); return CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { if (exc != null) System.err.println("WARNING: " + exc); return CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.err.println("WARNING: " + exc); return CONTINUE; } } static void usage() { System.err.println("java Chmod [-R] symbolic-mode-list file..."); System.exit(-1); } public static void main(String[] args) throws IOException { if (args.length < 2) usage(); int argi = 0; int maxDepth = 0; if (args[argi].equals("-R")) { if (args.length < 3) usage(); argi++; maxDepth = Integer.MAX_VALUE; } // compile the symbolic mode expressions Changer changer = compile(args[argi++]); TreeVisitor visitor = new TreeVisitor(changer); Set while (argi < args.length) { Path file = Paths.get(args[argi]); Files.walkFileTree(file, opts, maxDepth, visitor); argi++; } } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309# 用户定义的文件属性 ! 没有兴趣测试:原文链接 http://docs.oracle.com/javase/tutorial/essential/io/fileAttr.html 如果您的文件系统实现支持的文件属性不足以满足您的需要,您可以使用它 UserDefinedAttributeView 来创建和跟踪您自己的文件属性 一些实现将此概念映射到文件系统(如 ext3 和 ZFS)上的 NTFS 替代数据流和扩展属性等功能。 大多数实现对值的大小施加了限制,例如,ext3 将大小限制为 4 千字节。 Path file = ...; UserDefinedFileAttributeView view = Files .getFileAttributeView(file, UserDefinedFileAttributeView.class); view.write("user.mimetype", Charset.defaultCharset().encode("text/html"); 12345文件的 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(); 12345678# 文件存储属性 您可以使用 FileStore 该类来了解有关文件存储的信息,例如可用空间多少。该 getFileStore(Path) 方法将获取指定文件的文件存储。 以下代码片段将打印特定文件所在的文件存储区的空间使用情况: Path file = Paths.get("D:/"); // Path file = Paths.get("D:/server.xml"); // 就算给定一个文件,也只会使用根目录驱动器来作为基准 FileStore store = Files.getFileStore(file); long total = store.getTotalSpace() / 1024 / 1024 / 1024; long used = (store.getTotalSpace() - store.getUnallocatedSpace()) / 1024 / 1024 / 1024; long avail = store.getUsableSpace() / 1024 / 1024 / 1024; System.out.println("总容量:" + total + "G"); System.out.println("已使用:" + used); System.out.println("可用:" + avail); 12345678910