轉自
開發者的天空
管理元數據(文件屬性和文件存儲屬性)
在文件系統中,文件或者目錄的元數據是和文件或者目錄本身存儲在一起的,而且元數據保存了很多的信息,例如:
對象是文件還是目錄,抑或是符號鏈接。文件的大小、創建
時間、最后修改時間、文件的所有者、組、訪問權限等。
java.nio.file.attribute包提供了訪問和管理文件系統元數據(通常叫做文件屬性)的功能。不同的文件系統提供的文件屬性是不一樣
的,所以我們按照這個將文件的屬性劃分成了不同的視圖(View)。每個View對應一個文件系統的實現,如POSIX(Unix使用的文件系統)或
DOS;或者是所有文件系統共有的屬性,如文件的所有權。當我們讀取文件的屬性的時候,是一次讀取整個視圖的屬性的。
Java所支持的視圖有:
BasicFileAttributeView – 所有的文件系統實現都必須提供的屬性的視圖。
DosFileAttributeView – 擴展了BasicFileAttributeView,添加了DOS文件系統能夠支持的幾種屬性。
PosixFileAttributeView –
擴展了BasicFileAttributeView,添加了POSIX文件系統能夠支持的幾種屬性。
FileOwnerAttributeView – 任何文件系統實現都會支持文件所有者的屬性。這個View就包含這個屬性。
AclFileAttributeView –
支持讀取和更新文件的訪問控制列表。支持NFSv4訪問控制列表模型。所有定義了到NFSv4的映射的訪問控制列表模型也同樣支持,如Windows的訪
問控制列表模型。
UserDefinedFileAttributeView –
支持用戶自定義的元數據。這個View可以被映射到文件系統提供的擴展機制。例如在Solaris操作系統上,可以將這個View存儲MIMEtype。
不同的文件系統可能支持不同的一個或幾個view,也有可能含有上面所有的View都沒有包含的文件屬性。
Attributes類
大多數情況下,我們不需要直接使用FileAttributeView接口,Attributes類提供了轉換的方法來讀取和設置文件屬性。
下面是Attributes類提供的一些方法:
讀取或設置基本的文件屬性:
readBasicFileAttributes(FileRef, LinkOption...)
setLastAccessTime(FileRef, FileTime)
setLastModifiedTime(FileRef, FileTime)
讀取或設置POSIX文件屬性
readPosixFileAttributes(FileRef, LinkOption...)
setPosixFilePermissions(FileRef, Set<PosixFilePermission>)
讀取或設置文件的所有者
getOwner(FileRef)
setOwner(FileRef, UserPrincipal)
一次讀取所有的文件屬性
readAttributes(FileRef, String, LinkOption...)
讀取或設定特定的文件屬性
getAttribute(FileRef, String, LinkOption...)
setAttribute(FileRef, String, Object)
讀取DOS文件屬性
readDosFileAttributes(FileRef, LinkOption...)
讀取或設置文件的訪問控制列表。
getAcl(FileRef)
setAcl(FileRef, List<AclEntry>)
讀取文件存儲空間的屬性,如總空間、有效空間、未分配空間等。
readFileStoreSpaceAttributes(FileStore)
每個read方法都返回一個對象,該對象會提供訪問方法,我們通過這些訪問方法能夠很方便的獲得特定的文件屬性的值。
要想讀取基本的文件信息,那么可以調用readBasicFileAttributes(FileRef,
LinkOption...)方法。這個方法支持的LinkOption就只有NOFOLLOW_LINKS。這個方法會一次性的讀取所有的基本的文件屬
性并返回一個BasicFileAttributes對象,我們可以訪問該對象獲取具體的文件屬性。如果程序對文件沒有訪問權限,該方法會拋出
SecurityException異常。要注意的是,并不是所有文件系統的實現都支持創建時間、最后修改時間和最后訪問時間這三個屬性。如果某個屬性不
被支持,則調用該屬性的get方法時會返回null。下面就是一個讀取文件的基本屬性的例子:
Path file =
;
BasicFileAttributes attr = Attributes.readBasicFileAttributes(file);
if (attr.creationTime() != null) {
System.out.println("creationTime: " + attr.creationTime());
}
if (attr.lastAccessTime() != null) {
System.out.println("lastAccessTime: " + attr.lastAccessTime());
}
if (attr.lastModifiedTime() != null) {
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());
下面的例子中,我們檢查了對一個文件的訪問權限,判斷
該文件是常規的文件還是目錄:
import static java.nio.file.AccessMode.*;
Path file =
;
boolean error=false;
try {
file.checkAccess(READ, EXECUTE);
if (!Attributes.readBasicFileAttributes(file).isRegularFile()) {
error = true;
}
} catch (IOException x) {
//Logic for error condition
error = true;
}
if (error) {
//Logic for failure
return;
}
//Logic for executable file
設置
時間戳
前面的文件基本屬性的代碼中演示了怎樣獲取文件的時間戳,Attributes類還提供了兩個方法來設置時間戳:setLastAccessTime和
setLastModifiedTime,下面是這兩個方法的示例:
Path file =
;
BasicFileAttributes attr = Attributes.readBasicFileAttributes(file);
long currentTime = System.currentTimeMillis();
if (attr.lastModifiedTime() != null) {
FileTime ft = FileTime.fromMillis(currentTime);
Attributes.setLastModifiedTime(file, ft);
} else {
System.err.println("lastModifiedTime time stamp not supported");
}
DOS的文件屬性
要獲取一個文件的DOS的文件屬性,需要調用readDosFileAttributes方法。這個方法會返回一個DosFileAttributes對
象,該對象提供了獲取DOS文件屬性的方法,例如:
Path file =
;
try {
DosFileAttributes attr = Attributes.readDosFileAttributes(file);
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 (IOException x) {
System.err.println("DOS file attributes not supported:" + x);
}
我
們可以使用setAttribute方法來設置DOS文件屬性,如:
Path file =
;
Attributes.setAttribute(file, "dos:hidden", true);
要注意的是,不是只有DOS操作系統才支持DOS文
件屬性,有些操作系統如Samba也支持DOS文件屬性。
POSIX的文件屬性
POSIX是Portable Operation System Interface for
UNIX的縮寫,而且IEEE和ISO定義很多標準來保證不同的UNIX之間的戶操作性,因此對于開發人員來說,針對POSIX編寫的程序能夠很容易的運
行在不同的兼容POSIX的文件系統上。
要讀取POSIX文件屬性,需要調用readPosixFileAttributes方法。除了文件所有者和所屬組,POSIX還支持9種文件權限許可組
合:讀、寫、執行三種權限和文件所有者、同組的用戶和其他用戶三種角色的組合(3 × 3 = 9)。下面就是讀取POSIX文件屬性的簡單的例子:
Path file =
;
PosixFileAttributes attr = Attributes.readPosixFileAttributes(file);
System.out.format("%s %s %s%n", attr.owner().getName, attr.group().getName(),
PosixFilePermissions.toString(attr.permissions()));
下面的代碼讀取了一個文件的屬性,然后創建了一個新的
文件,將原有的文件的權限屬性賦予新創建的文件:
Path sourceFile =
;
Path newFile =
;
PosixFileAttributes attrs = Attributes.readPosixFileAttributes(sourceFile);
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(attrs.permissions());
try {
file.createFile(attr);
} catch (IOException x) {
//unable to create the file
}
上
面的代碼中我們使用了PosixFilePermission類,該類是一個幫助類,提供了一些方法來讀取和生成文件權限,這里就不詳細解釋了。
如果想指定創建的文件的權限,可以使用下面的代碼:
Path file =
;
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);
try {
Attributes.setPosixFilePermissions(file, perms);
} catch (IOException x) {
System.err.println(x);
}
文
件有所有者的屬性和所屬組的屬性,在設置這些屬性的時候,我們需要傳入一個UserPrincipal對象作為參數,我們可以使用
UserPrincipalLookupService來根據用戶名或組名來創建該對象。UserPrincipalLookupService實例可以
通過FileSystem.getUserPrincipalLookupService方法獲得。下面就是設置所有者屬性的例子:
Path file =
;
try {
UserPrincipal owner = file.GetFileSystem().getUserPrincipalLookupService()
.lookupPrincipalByName("sally");
Attributes.setOwner(file, owner);
} catch (IOException x) {
System.err.println(x);
}
Attributes
類沒有提供設置所屬組的方法,如果要設置所屬組,需要調用POSIX文件屬性視圖來進行,下面是示例代碼:
Path file =
;
try {
GroupPrincipal group = file.getFileSystem().getUserPrincipalLookupService()
.lookupPrincipalByGroupName("green");
file.getFileAttributeView(PosixFileAttributeView.class).setGroup(group);
} catch (IOException x) {
System.err.println(x);
}
用戶定義的文件屬性
如果文件系統支持的屬性對你來說還不夠用,你可以通過UserDefinedAttributeView來創建和跟蹤自己的文件屬性。
下面的例子中,我們將MIME類型作為一個用戶自定義的屬性:
Path file =
;
UserDefinedFileAttributeView view = file
.getFileAttributeView(UserDefinedFileAttributeView.class);
view.write("user.mimetype", Charset.defaultCharset().encode("text/html");
要讀取MIME類型屬性,要使用以下的代碼:
Path file =
;
UserDefinedFileAttributeView view = file
.getFileAttributeView(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();
如果文件系統不支持擴展屬性,那么會拋出一個
UnsupportedOperationException異常,你可以咨詢系統管理員來確認系統是否支持文件的擴展屬性并進行相應的配置。
文件存儲屬性
文件存儲屬性其實我們應該非常熟悉的屬性,我們查看硬盤屬性的時候,經常看到硬盤總的存儲空間,使用了的存儲空間,空閑的存儲空間等就是文件存儲屬性。下
面是獲取文件存儲屬性的代碼:
Path file =
;
FileStore store = file.getFileStore();
FileStoreSpaceAttributes attr = Attributes.readFileStoreSpaceAttributes(store);
System.out.println("total: " + attr.totalSpace() );
System.out.println("used: " + (attr.totalSpace() - attr.unallocatedSpace()) );
System.out.println("avail: " + attr.usableSpace() );