Trail: Essential Classes
Lesson: Basic I/O
Section: File I/O (Featuring NIO.2)
Managing Metadata (File and File Store Attributes)
Home Page > Essential Classes > Basic I/O
Managing Metadata (File and File Store Attributes)
The definition of metadata is "data about other data." With a file system, the data is contained in its files and directories, and the metadata tracks information about each of these objects: Is it a regular file, a directory, or a link? What is its size, creation date, last modified date, file owner, group owner, and access permissions?

The java.nio.file.attribute package provides an API to manage the file system's metadata, or file attributes, as it is typically called. Because different file systems have different notions about which attributes should be tracked, related file attributes are grouped together into views. A view maps to a particular file system implementation, such as POSIX or DOS, or to a common functionality, such as file ownership.

A view's attributes are read in one bulk operation. This allows for efficient access and bidirectional mapping for cases where the file attributes must be converted to and from the file system implementation.

The supported views are as follows:

A specific file system implementation might support only the basic file attribute view, or it may support several of these file attribute views. Lastly, a specific file system implementation might support other attribute views not included in this API.

This section covers the following:

Attributes Class

In most instances, you do not have to deal directly with any of the FileAttributeView interfaces. The Attributes class provides convenience methods for reading and setting file attributes. The examples in this lesson use the Attributes methods that are shown in the following table:

Method Comment
readBasicFileAttributes(FileRef, LinkOption...)
setLastAccessTime(FileRef, FileTime)
setLastModifiedTime(FileRef, FileTime)
Reads or sets basic file attributes.
readPosixFileAttributes(FileRef, LinkOption...)
setPosixFilePermissions(FileRef, Set<PosixFilePermission>)

Reads or sets a file's POSIX attributes.
getOwner(FileRef)
setOwner(FileRef, UserPrincipal)
Reads or sets the owner of the file.
readAttributes(FileRef, String, LinkOption...) Reads an entire set of attributes in one operation.
getAttribute(FileRef, String, LinkOption...)
setAttribute(FileRef, String, Object)
Reads or sets the value of a particular file attribute.
readDosFileAttributes(FileRef, LinkOption...) Reads a file's DOS attributes.
getAcl(FileRef)
setAcl(FileRef, List<AclEntry>)
Reads or sets a file's Access Control List (ACL). The AclEdit example shows how to edit a file's ACL. You can try the example with Solaris ZFS, Microsoft Windows NTFS, or any platform that supports ACLs.
readFileStoreSpaceAttributes(FileStore) Reads the space attributes (total, available, and unallocated space) of a file store.

Each of these read... methods (for example, readDosFileAttributes) returns an object (for example, DosFileAttributes) that provides accessor methods so that you can easily obtain the values of the specific file attributes.

Basic File Attributes

To read the basic attributes of a file, you can use the readBasicFileAttributes(FileRef, LinkOption...) method, which reads all the basic attributes in one bulk operation. This is far more efficient than accessing the file system separately to read each individual attribute. The varargs argument currently supports the LinkOption enum, NOFOLLOW_LINKS. Use this option when you do not want symbolic links to be followed.


A word about time stamps: The set of basic attributes includes three time stamps: creationTime, lastModifiedTime, and lastAccessTime. Any of these time stamps might not be supported in a particular implementation, in which case the corresponding accessor method returns null. When supported, the time stamp is returned as an FileTime object.

The readBasicFileAttributes method returns an instance of BasicFileAttributes, which provides a number of methods for retrieving the attribute information. The following code snippet reads and prints the basic file attributes for a given file.

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());

In addition to the accessor methods shown in this example, there is a fileKey method that returns either an object that uniquely identifies the file or null if no file key is available.

The Checking File Accessibility section showed an example that checked whether a file was executable by invoking the checkAccess method to examine the file's READ and EXECUTE bits. Of course, on UNIX systems, directories also use the EXECUTE bit to confer access permission to the directory. To determine whether a file is a regular file that can be executed (and not a directory), the example is extended to check the file type by using the basic file attributes.

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...

Setting Time stamps

The previous section shows how you can read time stamps by using the readBasicFileAttributes method. The Attributes class provides two methods for setting time stamps: setLastAccessTime and setLastModifiedTime. The following code snippet sets the last modified time in milliseconds:

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 File Attributes

DOS file attributes are also supported on file systems other than DOS, such as Samba.

To read the DOS attributes of a file, you can use the readDosFileAttributes(FileRef, LinkOption...) method. You can specify the NOFOLLOW_LINKS link option if you do not want any symbolic links to be followed.

This method returns an instance of DosFileAttributes, which provides methods for retrieving the DOS attributes, as follows:

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);
}

There are no special-purpose methods for setting a DOS attribute. However, you can do so by using the setAttribute(FileRef, String, Object) method, as follows:

Path file = ...;
Attributes.setAttribute(file, "dos:hidden", true);

POSIX File Permissions

POSIX is an acronym for Portable Operating System Interface for UNIX and is a set of IEEE and ISO standards designed to ensure interoperability among different flavors of UNIX. If a program conforms to these POSIX standards, it should be easily ported to other POSIX-compliant operating systems.

To read the POSIX file attributes, you can use the readPosixFileAttributes(FileRef, LinkOption...) method. Besides file owner and group owner, POSIX supports nine file permissions: read, write, and execute permissions for the file owner, members of the same group, and "everyone else."

The following code snippet reads the POSIX file attributes for a given file and prints them to standard output:

Path file = ...;
PosixFileAttributes attr = Attributes.readPosixFileAttributes(file);
System.out.format("%s %s %s%n", attr.owner().getName, attr.group().getName(),
                  PosixFilePermissions.toString(attr.permissions()));

The PosixFilePermissions helper class provides several useful methods, as follows:

  • The toString method, used in the previous code snippet, converts the file permissions to a string (for example, rw-r--r--).
  • The fromString method accepts a string representing the file permissions and constructs a Set of file permissions.
  • The asFileAttribute method accepts a Set of file permissions and constructs a file attribute that can be passed to the Path.createFile or Path.createDirectory method.

The following code snippet reads the attributes from one file and creates a new file, assigning the attributes from the original file to the new file:

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
}

The asFileAttribute method wraps the permissions as a FileAttribute. The code then attempts to create a new file with those permissions. Note that the umask also applies, so the new file might be more secure than the permissions that were requested.

To set a file's permissions to values represented as a hard-coded string, you can use the following code:

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);
}

The Chmod example recursively changes the permissions of files in a manner similar to the chmod utility.

Setting a File or Group Owner

To translate a name into an object you can store as a file owner or a group owner, you can use the UserPrincipalLookupService service. This service looks up a name or group name as a string and returns a UserPrincipal object representing that string. You can obtain the user principal look-up service for the default file system by using the FileSystem.getUserPrincipalLookupService method.

The following code snippet shows how to set the file owner by using the setOwner method:

Path file = ...;
try {
    UserPrincipal owner = file.GetFileSystem().getUserPrincipalLookupService()
                          .lookupPrincipalByName("sally");
    Attributes.setOwner(file, owner);
} catch (IOException x) {
    System.err.println(x);
}

There is no special-purpose method in the Attributes class for setting a group owner. However, a safe way to do so directly is through the POSIX file attribute view, as follows:

Path file = ...;
try {
    GroupPrincipal group = file.getFileSystem().getUserPrincipalLookupService()
                          .lookupPrincipalByGroupName("green");
    file.getFileAttributeView(PosixFileAttributeView.class).setGroup(group);
} catch (IOException x) {
    System.err.println(x);
}

User-Defined File Attributes

If the file attributes supported by your file system implementation aren't sufficient for your needs, you can use the UserDefinedAttributeView to create and track your own file attributes.

Some implementations map this concept to features like NTFS Alternative Data Streams and extended attributes on file systems such as ext3 and ZFS. Most implementations impose restrictions on the size of the value, for example, ext3 limits the size to 4 kilobytes.

A file's MIME type can be stored as a user-defined attribute by using this code snippet:

Path file = ...;
UserDefinedFileAttributeView view = file
    .getFileAttributeView(UserDefinedFileAttributeView.class);
view.write("user.mimetype", Charset.defaultCharset().encode("text/html");

To read the MIME type attribute, you would use this code snippet:

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();

The Xdd example shows how to get, set, and delete a user-defined attribute.


Note: In Linux, you might have to enable extended attributes for user-defined attributes to work. If you receive an UnsupportedOperationException when trying to access the user-defined attribute view, you need to remount the file system. The following command remounts the root partition with extended attributes for the ext3 file system. If this command does not work for your flavor of Linux, consult the documentation.

$ sudo mount -o remount,user_xattr /
If you want to make the change permanent, add an entry to /etc/fstab.

File Store Attributes

You can use the readFileStoreSpaceAttributes(FileStore) method to learn how much space is available on a file store.

The following code snippet prints the space usage for the file store where a particular file resides:

Path file = ...;
FileStore store = file.getFileStore();
FileStoreSpaceAttributes attr = Attributes.readFileStoreSpaceAttributes(store);

long total = attr.totalSpace() / 1024;
long used = (attr.totalSpace() - attr.unallocatedSpace()) / 1024;
long avail = attr.usableSpace() / 1024;

System.out.println("store: " + store);
System.out.println("total: " + attr.totalSpace() / 1024);
System.out.println("used:  " + (attr.totalSpace() - attr.unallocatedSpace()) / 1024);
System.out.println("avail: " + attr.usableSpace() / 1024);

The DiskUsage example uses this API to print disk space information for all the stores in the default file system. This example uses the getFileStores method in the FileSystem class to fetch all the file stores for the the file system.

Previous page: Moving a File or Directory
Next page: Reading, Writing, and Creating Files