1. Overview
1.概述
In this article, we are going to explore one of the advanced features of the Java 7 NIO.2 filesystem APIs – specifically file attribute APIs.
在这篇文章中,我们将探讨Java 7 NIO.2文件系统API的一个高级功能–特别是文件属性API。
We have previously covered the File and Path APIs if you want to dig deeper into these foundational pieces first.
我们之前已经介绍了文件和路径 API,如果您想先深入了解这些基础部分。
All the files required to handle filesystem operations are bundled up in the java.nio.file package:
处理文件系统操作所需的所有文件都捆绑在java.nio.file包中。
import java.nio.file.*;
2. Basic File Attributes
2.基本文件属性
Let’s start with a high-level view of the basic attributes common to all file systems – provided by the BasicFileAttributeView – which stores all mandatory and optional visible file attributes.
让我们从所有文件系统共有的基本属性的高级视图开始–由BasicFileAttributeView提供–它存储了所有强制性和可选的可见文件属性。
We can explore the basic attributes of the user home location on the current machine, by creating a path to HOME and getting it’s basic attribute view:
我们可以通过创建一个通往HOME的路径并获得它的基本属性视图,来探索用户在当前机器上的home位置的基本属性。
String HOME = System.getProperty("user.home");
Path home = Paths.get(HOME);
BasicFileAttributeView basicView =
Files.getFileAttributeView(home, BasicFileAttributeView.class);
After the above step, we can now read all the attributes of the path pointed to in one bulk operation:
经过上述步骤,我们现在可以在一次批量操作中读取指向的路径的所有属性。
BasicFileAttributes basicAttribs = basicView.readAttributes();
We are now in a position to explore different common attributes which we can actually use in our applications especially in conditional statements.
我们现在可以探索不同的共同属性,我们可以在我们的应用程序中实际使用,特别是在条件语句中。
We can query for the size of the file from its basic attributes container:
我们可以从其基本属性容器中查询文件的大小。
@Test
public void givenPath_whenGetsFileSize_thenCorrect() {
long size = basicAttribs.size();
assertTrue(size > 0);
}
We can also check if it’s a directory:
我们还可以检查它是否是一个目录。
@Test
public void givenPath_whenChecksIfDirectory_thenCorrect() {
boolean isDir = basicAttribs.isDirectory();
assertTrue(isDir);
}
Or a regular file:
或者一个普通的文件。
@Test
public void givenPath_whenChecksIfFile_thenCorrect() {
boolean isFile = basicAttribs.isRegularFile();
assertFalse(isFile);
}
With Java NIO.2 we are now able to deal with symbolic links or soft links in the file system. These are files or directories which we normally call shortcuts.
通过Java NIO.2,我们现在能够处理文件系统中的符号链接或软链接。这些是文件或目录,我们通常称之为快捷方式。
To check if a file is a symbolic link:
要检查一个文件是否是一个符号链接。
@Test
public void givenPath_whenChecksIfSymLink_thenCorrect() {
boolean isSymLink = basicAttribs.isSymbolicLink();
assertFalse(isSymLink);
}
In rare cases, we can call the isOther API to check if the file belongs to none of the common categories of regular file, directory or symbolic link:
在极少数情况下,我们可以调用isOther API来检查该文件是否属于普通文件、目录或符号链接等常见类别。
@Test
public void givenPath_whenChecksIfOther_thenCorrect() {
boolean isOther = basicAttribs.isOther();
assertFalse(isOther);
}
To get the time the file was created:
要获得文件的创建时间。
FileTime created = basicAttribs.creationTime();
To get the last modified time:
要获得最后的修改时间。
FileTime modified = basicAttribs.lastModifiedTime();
And to get the last access time:
并获得最后的访问时间。
FileTime accessed = basicAttribs.lastAccessTime();
All the above examples return a FileTime object. This is a more usable abstraction than a mere timestamp.
上述所有的例子都返回一个FileTime对象。这是一个比单纯的时间戳更有用的抽象。
For example, we can easily compare two file times to know which event occurred before or after the other:
例如,我们可以很容易地比较两个文件的时间,以了解哪个事件发生在另一个之前或之后。
@Test
public void givenFileTimes_whenComparesThem_ThenCorrect() {
FileTime created = basicAttribs.creationTime();
FileTime modified = basicAttribs.lastModifiedTime();
FileTime accessed = basicAttribs.lastAccessTime();
assertTrue(0 >= created.compareTo(accessed));
assertTrue(0 <= modified.compareTo(created));
assertTrue(0 == created.compareTo(created));
}
The compareTo API works the same way as for other comparables in Java. It returns a negative value in case the object it’s being called on is less than the argument; in our case, creation time definitely comes before access time as in the first assertion.
compareTo API的工作方式与Java中的其他比较器相同。如果被调用的对象小于参数,它就会返回一个负值;在我们的例子中,创建时间肯定在访问时间之前,就像第一个断言一样。
In the second assertion, we get a positive integer value because a modification can only be made after a creation event. And finally, it returns 0 when the times being compared are equal.
在第二个断言中,我们得到一个正的整数值,因为只有在创建事件之后才能进行修改。最后,当被比较的时间相等时,它返回0。
When we have a FileTime object, we can then convert it to most other units depending on our needs; days, hours, minutes, seconds, milliseconds and so on. We do this by calling the appropriate API:
当我们有一个FileTime对象时,我们可以根据我们的需要将其转换为大多数其他单位;天、小时、分钟、秒、毫秒等等。我们通过调用适当的API来实现这一目的。
accessed.to(TimeUnit.SECONDS);
accessed.to(TimeUnit.HOURS);
accessed.toMillis();
We can as well print a human readable form of the file time by calling its toString API:
我们也可以通过调用其toString API来打印一个人类可读的文件时间形式。
accessed.toString();
Which prints something useful in ISO time format:
它以ISO时间格式打印出一些有用的东西。
2016-11-24T07:52:53.376Z
We can also change the time attributes on the view by calling its setTimes(modified, accessed, created) API. We pass in the new FileTime objects where we want to change or null where we don’t want to change.
我们还可以通过调用其 setTimes(modified, accessed, created) API来改变视图的时间属性。我们在想要改变的地方传入新的FileTime对象,在不想改变的地方传入空对象。
To change the last access time one minute into the future, we would follow these steps:
要改变未来一分钟的最后访问时间,我们要遵循以下步骤。
FileTime newAccessTime = FileTime.fromMillis(
basicAttribs.lastAccessTime().toMillis() + 60000);
basicView.setTimes(null, newAccessTime , null);
This change will persist in the actual file as seen from any other application running on the machine and using the file system.
这一变化将在实际文件中持续存在,因为从任何其他在机器上运行并使用该文件系统的应用程序可以看到。
3. File Space Attributes
3.文件空间属性
When you open my computer on Windows, Linux or Mac, you can usually see a graphic analysis of space information about you storage drives.
当你在Windows、Linux或Mac上打开我的电脑时,你通常可以看到关于你存储驱动器的空间信息的图形分析。
Java NIO.2 makes this kind of high-level functionality very easy. It interacts with the underlying file system to retrieve this information while we only have to call simple APIs.
Java NIO.2使这种高级功能变得非常容易。它与底层文件系统交互以检索这些信息,而我们只需要调用简单的API。
We can use the FileStore class to inspect storage drives and obtain important information such as it’s size, how much space is used and how much is still unused.
我们可以使用FileStore类来检查存储驱动器,并获得重要的信息,如它的大小,有多少空间被使用,有多少仍未使用。
To get a FileStore instance for the location of an arbitrary file in the file system, we use the getFileStore API of Files class:
为了获得一个FileStore实例,以获得文件系统中一个任意文件的位置,我们使用Files类的getFileStore API。
Path file = Paths.get("file");
FileStore store = Files.getFileStore(file);
This FileStore instance specifically represents the file store where the specified file is located, not the file itself. To get total space:
这个FileStore实例具体代表指定文件所在的文件存储空间,而不是文件本身。要获得总空间。
long total = store.getTotalSpace();
To get used space:
为了获得使用的空间。
long used = store.getTotalSpace() - store.getUnallocatedSpace();
We are less likely to follow this approach than the next.
我们不太可能遵循这种方法,而不是下一个。
More commonly, we are likely to get information about storage information about all file stores. To emulate my computer’s graphic drive space information in a program we can use FileSystem class to enumerate the file stores:
更常见的是,我们有可能获得关于所有文件存储空间的存储信息。为了在程序中模拟我的电脑的图形驱动器空间信息,我们可以使用文件系统类来列举文件存储。
Iterable<FileStore> fileStores = FileSystems.getDefault().getFileStores();
We can then loop over the returned values and do whatever we need to do with the information, such as updating a graphical user interface:
然后,我们可以在返回的值上循环,做任何我们需要做的事情,比如更新一个图形用户界面。
for (FileStore fileStore : fileStores) {
long totalSpace = fileStore.getTotalSpace();
long unAllocated = fileStore.getUnallocatedSpace();
long usable = fileStore.getUsableSpace();
}
Note that all the returned values are in bytes. We can convert to suitable units as well as calculating other information such as used space using basic arithmetic.
注意,所有返回的值都是以字节为单位。我们可以转换为合适的单位,以及使用基本算术计算其他信息,如使用的空间。
The difference between unallocated space and usable space is in accessibility to the JVM.
未分配空间和可用空间的区别在于JVM的可访问性。
Usable space is the space available to the JVM while unallocated space is the available space as seen by the underlying file system. Therefore, usable space may sometimes be smaller than unallocated space.
可用空间是JVM可用的空间,而未分配的空间是底层文件系统看到的可用空间。因此,可用空间有时可能比未分配的空间小。
4. File Owner Attributes
4.文件所有者属性
To inspect file ownership information, we use the FileOwnerAttributeView interface. It gives us a high-level view of the ownership information.
为了检查文件所有权信息,我们使用FileOwnerAttributeView接口。它为我们提供了一个所有权信息的高层视图。
We can create a FileOwnerAttributeView object like this:
我们可以像这样创建一个FileOwnerAttributeView对象。
Path path = Paths.get(HOME);
FileOwnerAttributeView ownerView = Files.getFileAttributeView(
attribPath, FileOwnerAttributeView.class);
To get the owner of the file from the above view:
要从上述视图中获得文件的所有者。
UserPrincipal owner = ownerView.getOwner();
There is really nothing much we can do programmatically with the above object, apart from getting the name of the owner for some other arbitrary purpose:
除了为其他任意的目的获取所有者的名字之外,我们对上述对象真的没有什么可以用程序来做的。
String ownerName = owner.toString();
5. User Defined File Attributes
5.用户定义的文件属性
There are scenarios where the file attributes defined in the file system are not sufficient for your needs. Should you come across such a case and require to set your own attributes on a file, then the UserDefinedFileAttributeView interface will come in handy:
有些情况下,文件系统中定义的文件属性并不能满足你的需求。如果你遇到这种情况,需要在文件上设置自己的属性,那么UserDefinedFileAttributeView接口将派上用场。
Path path = Paths.get("somefile");
UserDefinedFileAttributeView userDefView = Files.getFileAttributeView(
attribPath, UserDefinedFileAttributeView.class);
To retrieve the list of user defined attributes already defined for the file represented by the above view:
要检索已经为上述视图所代表的文件定义的用户属性的列表。
List<String> attribList = userDefView.list();
To set a user-defined attribute on the file, we use the following idiom:
要在文件上设置一个用户定义的属性,我们使用以下成语。
String name = "attrName";
String value = "attrValue";
userDefView.write(name, Charset.defaultCharset().encode(value));
When you need to access the user defined attributes, you can loop over the attribute list returned by the view and inspect them using this idiom:
当你需要访问用户定义的属性时,你可以循环浏览视图返回的属性列表,并使用这个习惯法来检查它们。
ByteBuffer attrValue = ByteBuffer.allocate(userView.size(attrName));
userDefView.read(attribName, attribValue);
attrValue.flip();
String attrValue = Charset.defaultCharset().decode(attrValue).toString();
To remove a user-defined attribute from the file, we simply call the delete API of the view:
要从文件中删除一个用户定义的属性,我们只需调用视图的删除API。
userDefView.delete(attrName);
6. Conclusion
6.结论
In this article, we have explored some of the less commonly used features available in the Java 7 NIO.2 filesystem APIs, specifically file attribute APIs.
在这篇文章中,我们探讨了Java 7 NIO.2文件系统API中的一些不太常用的功能,特别是文件属性API。
The full source code for the examples used in this article is available in the Github project.
本文中所使用的例子的完整源代码可在Github项目中找到。