File Attributes in NIO.2

One of the biggest problems with pre-NIO.2 libraries was inefficient work with metadata of files and directories. Authors of NIO.2 library introduce concept of file attribute views to address this problem and also to solve couple of other issues that are dependent on this one. These problems included inability to create files with file attributes initialized at the creation time, inability to copy files with file attributes as well as problematic and inefficient way of handling file attributes. This concept was also adapted on file stores so the work with file system with regard to attributes and metadata feels seamless and consistent.

File attribute views

First thing that needs to be understood is the role of file attribute view. File system metadata is typically referred to as its file attributes. Most of these metadata can be categorized and segmented based on area of use / scope they are describing or their origin. To support this segmentation further, NIO.2 introduces file attributes views that preserve this natural grouping and provide consistent access to file system metadata via set of interfaces and concrete classes.

There are a few types of attribute views that we need to know in order to fully harness true power of this part of the library. Every standard file attribute view has a short name that is usually used for checking whether given view is supported and for quick addressing of single attribute. Lets take a look at six most important views:

BasicFileAttributeView

View name: basic

As the title suggests the most basic view that must be supported by all file system implementations. Provides access to information like lastModifiedTime, lastAccessTime, creationTime, size and few other.

AclFileAttributeView

View name: acl

View allowing programmer to control ACL settings of given file. Involves work with AclEntry objects.

FileOwnerFileAttributeView

View name: owner

View giving access to ownership information of a file. Allows programmer to get owners name or to set user principals. Involves work with UserPrincipal objects.

View extending BasicFileAttributesView that adds support for working with POSIX (Portable Operating System Interface for Unix) file attributes such as group, owner and permisions.

UserDefinedFileAttributeView

Does not have a name

View enabling work with user-created metadata.

But how does one find out what they are and whether they are supported on their concrete file system? Well this has been all taken care of. Programmer can retrieve a list of all supported file attribute views from every single concrete file system implementation. Lets examine following snippet:

As we can see supported file views are strongly implementation and platform dependent. However, all file system implementations should support basic file attribute view. Whether certain file attribute view is supported or not lies entirely on file store implementation. Since not all file attribute views are supported it is crucial to be able to tell, whether one can be used or not. Each attribute view serves different purposes, so programmer needs to be familiar with detailed structure of the views, when designing their code. Lets take a look at the following code sample and examine the way to check for view support:

Java

1

2

3

4

for(FileStore fs:FileSystems.getDefault().getFileStores()){

// returns true

fs.supportsFileAttributeView(BasicFileAttributeView.class);

}

Attribute views are always implementation and platform dependent so lets look at file system abstraction for ZIP files:

As we can see in file system example , neither acl nor dos views are supported. For a convenience reasons file system implementations provide method supportedFileAttributeViews that allows us to see what range of views is available to us.

File attributes reading and modification

As mentioned above the retrieval of a single file attribute means accessing the file system. In previous versions of IO libraries the only way to retrieve a group of n attributes was to do n accesses to the file system which was not only slow but also not an elegant solution. When it comes to the way NIO.2 handles this situation, simplicity and elegance are one of key elements.

First thing I am going to demonstrate is how to get attributes from desired view. This can be done in two (not that different) ways. You either retrieve the view object where you can read attributes or you can use method for reading attributes directly. Both ways include work with class java.nio.file.Files. To get a file attribute view just call method getFileAttributes with a path of the file and class of desired view. Then just call readAttributes to receive attributes object that you can query for supported attributes. On the other hand programmer can call readAttributes directly on Files class and get the same output, as demonstrated in following snippet:

Why are there two ways of doing this and not just one you ask? Well, there is big difference between file attribute views and their attributes objects that I have not described yet. Difference becomes apparent when we examine both classes closely. While attributes object is sort of transfer object that stores supported attributes for given view and provides us only getter methods to read them, view object is more powerful and informative. Views give us the ability to get attributes objects to get and set attribute values and some other (more complex) setter methods. For example PosixFileAttributeView has methods for setting owner group or file permissions. In this way each view is unique and may provide more advanced functionality than attributes objects.

However, there are situations when programmer does not need to work with group of file attributes and may want to get one particular attribute. Files class has a method to do just that. The only thing that changes is the syntax used in method getAttribute that specifies concrete attribute. There is also a setter method setAttribute that follows same rules. Each attribute view provides a table of all supported attributes with their names as well as the name of this view in its javadoc. Look at the BasicFileAttributeView example from current version of its javadoc:

File attributes supported by BasicFileAttributeView

Name

Type

lastModifiedTime

FileTime

lastAccessTime

FileTime

creationTime

FileTime

size

Long

isRegularFile

Boolean

isDirectory

Boolean

isSymbolicLink

Boolean

isOther

Boolean

fileKey

Object

These names are used to specify what attribute you want to work with. To specify what attribute to work with use the following scheme: <viewName>:<attributeName>. BasicFileAttributeView is special in a way that you can declare only the name of desired attribute without the need to specify view. All non-prefixed attributes are assumed to be from basic file attribute view. Lets look at the following code snippet that provides an example of this:

One can clearly see one major disadvantage of this approach. In order to use this technique properly programmer needs to be aware of the type of returned attributes value, whether by heart or by consulting the javadoc. Since we are using an explicit downcast we loose type safety of Java and open doors for unwanted runtime exceptions.

Now that we can read file attributes lets try to modify them. To demonstrate this I decided to change the owner of a file on ext4 file system. In order to do so, first look at class UserPrincipalLookupService and UserPrincipal from package java.nio.file.attribute. UserPrincipal represents an identity that is used to determine access rights to file system objects. UserPrincipalLookupService is an object that allows programmer to look up and use UserPrincipal objects in code. In order to modify the owner attribute I am going to use the direct approach of setting one attribute via Files class since it is the only one attribute I am interested in. You can observe the use of posix:owner syntax mentioned in previous paragraph for setting a non-basic file attribute. Following code snippet toggles the owner from a user to root and reverse.

*Please note that in case of this kind of modification the process must be run with an appropriate user privileges (in this case by root)

With an output:

1

2

Attribute 'owner' before: root

Attribute 'owner' after: jstas

Another great example of file attribute modification is changing of access permissions for a given file. This code modifies current access permissions and demonstrates the use of view object when an attribute object just will not cut it. Before running this code I changed permissions of the file via system terminal by running:

*Please note that in case of this kind of modification the process must be run with an appropriate user privileges (in this case by root)

With an output:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Permissions before modification:

GROUP_EXECUTE

OTHERS_WRITE

OWNER_EXECUTE

OWNER_WRITE

OTHERS_READ

GROUP_READ

GROUP_WRITE

OTHERS_EXECUTE

OWNER_READ

Permissions after modification:

OWNER_EXECUTE

OWNER_WRITE

OWNER_READ

These simple steps are universal to working with any type of view or attributes object. Feel free to experiment and try new ways to modify file attributes on your own.

User defined file attributes

Last chapter of this post is dedicated to creation of custom file attributes. To allow this, creators of NIO.2 library defined an extra view called UserDefinedFileAttributeView that allows programmer to create, read, update and delete user defined metadata for given file. This view is located in java.nio.file.attribute package. Attributes are saved as a key-value pairs. First of all, lets look at the way of reading all user defined attributes which follows standard procedure for reading standard attributes with a small change. First we need to get a view instance using Files class. UserDefinedFileAttributeView provides method list that lists names of all user defined attributes currently present on the file. Sample code to read these could look as follows:

When it comes to creation of such an attributes there is simple way to do so using write method on your view instance. Since all attribute values are stored as strings we need to do conversion of desired value. Keep in mind that this string value should not be encoded using default charset. Always use one of the standard charsets available in class StandardCharsets from package java.nio.charset and be consistent in your choice throughout the application. And definition of a new user defined attribute is done in following way:

There is no special method for updating the value of user defined attribute so we, once again, use write method to do the job (which makes the use of if statement in previous example obsolete – only prevents updating of the attribute).

However, when it comes to reading an user defined attribute, this is the part where things get a little complicated. In order to read this type of attribute developer needs to use a byte buffer to do charset decoding of the value. Since every user defined attribute contains information about its size we need to get this value to allocate our ByteBuffer instance properly. Then ask the view to fill this buffer with data and flip it. Flipping is done by calling flip method on the buffer itself. This sets the limit to current position in the buffer and then the position is set to zero. This way there is no problem to decode its contents using standard charset. Whole situation is shown in the following code snippet:

To see the whole process of reading, creating, modifying and deleting user defined attributes please follow this next code snippet. Notice that even though I added three file attributes size of the file remains constant. This behavior is platform dependent so consult documentation for your particular file system.

3 comments on “File Attributes in NIO.2”

Good article, helpful… but not for mac programmers as a mac system only supports ‘owner’, ‘basic’,’posix’, and a ‘unix’ – Macs do not support user defined file attributes nor acl so i am having a real hard time setting those extended file attributes (like author for example) on a mac… I can write the code to do it on a PC in my sleep…. really wish i could find a good mac example of how to do this…

1 Pings/Trackbacks for "File Attributes in NIO.2"

[…] is the fact that they are in fact files. This means that they have their own file system metadata (file attributes). One important thing to bear in mind is the fact the creation of symbolic link and population of […]