How to read file attributes with Java NIO

dimitrilc 3 Tallied Votes 275 Views Share

Introduction

The java.nio.file.Files class includes many convenient methods to read file attributes, but sometimes these convenient methods just are not enough to meet our needs.

In this tutorial, we will go over 5 ways to use the Files class to read file attributes so you can choose the best way for your use case.

Goals

At the end of the tutorial, you would have learned:

  1. 5 different ways to view file attributes with Java NIO.

Prerequisite Knowledge

  1. Basic Java.
  2. Java NIO/IO.

Tools Required

  1. A Java IDE such as IntelliJ Community Edition or Eclipse.

Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Java project.

  2. Create a package com.example.

  3. Create a class called Entry.

  4. Create the main() method inside Entry.java.

  5. Copy and paste the following content into the main() method.

     Path path = Path.of(".", "Test.txt");
    
     createTestFile(path);
    
     viewAttributes1(path);
     viewAttributes2(path);
     viewAttributes3(path);
     viewAttributes4(path);
     viewAttributes5(path);
  6. Create the creatTestFile() method like below:

     private static void createTestFile(Path path){
        try {
            if (Files.notExists(path))
                Files.createFile(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
     }
  7. The code will not compile yet because we are missing those viewAttributes() methods, which we will add later.

Read file attributes using convenient methods

As of Java 17, the Files class has 10 convenient methods to read file attributes. They are great to use because they are idiomatic and are very readable.

    Files.getLastModifiedTime(path); //1
    Files.isDirectory(path); //2
    Files.isRegularFile(path); //3
    Files.isSymbolicLink(path); //4
    Files.isExecutable(path); //5
    Files.isHidden(path); //6
    Files.isReadable(path); //7
    Files.isWritable(path); //8
    Files.size(path); //9
    Files.getOwner(path); //10

Let us create the first viewAttributes() method from the code below using the convenient methods from Files (put all of them inside the Entry class).

    private static void viewAttributes1(Path path) {
       try {
           Files.getLastModifiedTime(path); //1

           Files.isDirectory(path); //2
           Files.isRegularFile(path); //3
           Files.isSymbolicLink(path); //4

           Files.isExecutable(path); //5
           Files.isHidden(path); //6

           Files.isReadable(path); //7
           Files.isWritable(path); //8

           Files.size(path); //9

           Files.getOwner(path); //10
       } catch (IOException e){
           System.out.println(e);
       }
    }

Read file attributes from an AttributesView object

Besides using the convenient methods from Files, we can also use the AttributeView implementations. AttributeView is the top interface in the hierarchy of file attribute views, as depicted in the picture below.

AttributeView.png

For this tutorial, we are only concerned about the DosFileAttributeView (or you can substitute for PosixFileAttributeView if you are using Linux/Mac).

The BasicFileAttributeView supports file attributes in multiple file systems, so it can be used on any file system, but some attributes are specific to the operating systems, so we need to use the Dos/Posix attribute views to access those.

To get the FileAttributeView object, we can use the method Files.getFileAttributeView(). Its signature is below:

static <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options)

The only thing that is special about the above method is that we need to pass in the Class object of the FileAttributeView that we want (dos or posix). After we get the AttributeView object that we want, we can call the method readAttributes() on the AttributeView implementation and access the supported file attributes.

Create the viewAttributes2() method like the code below.

    private static void viewAttributes2(Path path){
       try {
           DosFileAttributes attributes = Files
                   .getFileAttributeView(path, DosFileAttributeView.class)
                   .readAttributes();

           attributes.lastModifiedTime(); //1
           attributes.lastAccessTime(); //2
           attributes.creationTime(); //3

           attributes.isDirectory(); //4
           attributes.isRegularFile(); //5

           attributes.isSymbolicLink(); //6
           attributes.isOther(); //7
           attributes.fileKey(); //8

           attributes.size(); //9

           attributes.isHidden(); //10
           attributes.isSystem(); //11
           attributes.isArchive(); //12
           attributes.isReadOnly(); //13
       } catch (IOException e) {
           e.printStackTrace();
       }
    }

As you can see, we now have 13 methods to read file attributes, which are 3 more than the convenient Files methods(although not all of them overlap).

Read file attributes from a BasicFileAttributes object

Besides the View object, it is also possible to use the BasicFileAttributes object itself (with implementation-specific variants as well). To get back a DosFileAttributes object, use the Files.readAttributes() object with the signature below.

    static <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)

Because we receive the DosFileAttributes object directly from this method, we can just access these attributes right away.
Create the viewAttributes3() method from the code below.

    private static void viewAttributes3(Path path){
       try {
           DosFileAttributes attributes = Files.readAttributes(path, DosFileAttributes.class); //similar to viewAttributes2()

           attributes.lastModifiedTime(); //1
           attributes.lastAccessTime(); //2
           attributes.creationTime(); //3

           attributes.isDirectory(); //4
           attributes.isRegularFile(); //5

           attributes.isSymbolicLink(); //6
           attributes.isOther(); //7
           attributes.fileKey(); //8

           attributes.size(); //9

           attributes.isHidden(); //10
           attributes.isSystem(); //11
           attributes.isArchive(); //12
           attributes.isReadOnly(); //13
       } catch (IOException e){
           e.printStackTrace();
       }
    }

As you can see, the functionality is technically the same as the previous method. With the View objects, we are able to modify the file attributes, whereas with just the Attributes objects, we can only read.

Read individual file attributes

The BasicFileAttributes and BasicFileAttributeView objects allow for reading attributes in bulk, but what if we only want to read a specific attribute that is implementation specific? Files.getAttributes() is what we need to use in this case. Its method signature is:

    public static Object getAttribute(Path path, String attribute, LinkOption... options) throws IOException

This time, we are no longer passing in the Class objects, but a String in a specific format.

    [view-name:]attribute-list

To mirror the functionalities of the DosFileAttributes object in the previous section, we create the viewAttributes4() method like below.

    public static void viewAttributes4(Path path){
       try {
           Files.getAttribute(path, "dos:lastModifiedTime"); //1
           Files.getAttribute(path, "dos:lastAccessTime"); //2
           Files.getAttribute(path, "dos:creationTime"); //3

           Files.getAttribute(path, "dos:size"); //4

           Files.getAttribute(path, "dos:isRegularFile"); //5
           Files.getAttribute(path, "dos:isDirectory"); //6
           Files.getAttribute(path, "dos:isSymbolicLink"); //7

           Files.getAttribute(path, "dos:isOther"); //8

           Files.getAttribute(path, "dos:fileKey"); //9

           Files.getAttribute(path, "dos:readonly"); //10

           Files.getAttribute(path, "dos:hidden"); //11

           Files.getAttribute(path, "dos:system"); //12
           Files.getAttribute(path, "dos:archive"); //13
       } catch (IOException e){
           e.printStackTrace();
       }
    }

The part of the string before the colon is the view name, which is the same as any of the AttributeView implementation’s name() method. The part after the colon is the attribute name.

Read file attributes as a Map

There is another method that allows for reading file attributes directly into a Map, and its signature is:

    public static Map<String,Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException

Note that this method also takes the String form like the Files.getAttribute() method, but if we want to read all of the attributes, we do not have to provide all of the attribute names. Instead, we can just provide a wildcard character to get all of the attributes into a Map.

Create the viewAttributes5() method like below.

    public static void viewAttributes5(Path path){
       try {
           Map<String, Object> attrMap = Files.readAttributes(path, "dos:*"); //gets a Map
       } catch (IOException e){
           e.printStackTrace();
       }
    }

Solution Code

    package com.example;

    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.attribute.*;
    import java.util.Map;

    public class Entry {
       public static void main(String[] args){
           Path path = Path.of(".", "Test.txt");

           createTestFile(path);

           viewAttributes1(path);
           viewAttributes2(path);
           viewAttributes3(path);
           viewAttributes4(path);
           viewAttributes5(path);
       }

       private static void createTestFile(Path path){
           try {
               if (Files.notExists(path))
                   Files.createFile(path);
           } catch (IOException e) {
               e.printStackTrace();
           }
       }

       private static void viewAttributes1(Path path) {
           try {
               Files.getLastModifiedTime(path); //1

               Files.isDirectory(path); //2
               Files.isRegularFile(path); //3
               Files.isSymbolicLink(path); //4

               Files.isExecutable(path); //5
               Files.isHidden(path); //6

               Files.isReadable(path); //7
               Files.isWritable(path); //8

               Files.size(path); //9

               Files.getOwner(path); //10
           } catch (IOException e){
               System.out.println(e);
           }
       }

       private static void viewAttributes2(Path path){
           try {
               DosFileAttributes attributes = Files
                       .getFileAttributeView(path, DosFileAttributeView.class)
                       .readAttributes();

               attributes.lastModifiedTime(); //1
               attributes.lastAccessTime(); //2
               attributes.creationTime(); //3

               attributes.isDirectory(); //4
               attributes.isRegularFile(); //5

               attributes.isSymbolicLink(); //6
               attributes.isOther(); //7
               attributes.fileKey(); //8

               attributes.size(); //9

               attributes.isHidden(); //10
               attributes.isSystem(); //11
               attributes.isArchive(); //12
               attributes.isReadOnly(); //13
           } catch (IOException e) {
               e.printStackTrace();
           }
       }

       private static void viewAttributes3(Path path){
           try {
               DosFileAttributes attributes = Files.readAttributes(path, DosFileAttributes.class); //similar to viewAttributes2()

               attributes.lastModifiedTime(); //1
               attributes.lastAccessTime(); //2
               attributes.creationTime(); //3

               attributes.isDirectory(); //4
               attributes.isRegularFile(); //5

               attributes.isSymbolicLink(); //6
               attributes.isOther(); //7
               attributes.fileKey(); //8

               attributes.size(); //9

               attributes.isHidden(); //10
               attributes.isSystem(); //11
               attributes.isArchive(); //12
               attributes.isReadOnly(); //13
           } catch (IOException e){
               e.printStackTrace();
           }
       }

       public static void viewAttributes4(Path path){
           try {
               Files.getAttribute(path, "dos:lastModifiedTime"); //1
               Files.getAttribute(path, "dos:lastAccessTime"); //2
               Files.getAttribute(path, "dos:creationTime"); //3

               Files.getAttribute(path, "dos:size"); //4

               Files.getAttribute(path, "dos:isRegularFile"); //5
               Files.getAttribute(path, "dos:isDirectory"); //6
               Files.getAttribute(path, "dos:isSymbolicLink"); //7

               Files.getAttribute(path, "dos:isOther"); //8

               Files.getAttribute(path, "dos:fileKey"); //9

               Files.getAttribute(path, "dos:readonly"); //10

               Files.getAttribute(path, "dos:hidden"); //11

               Files.getAttribute(path, "dos:system"); //12
               Files.getAttribute(path, "dos:archive"); //13
           } catch (IOException e){
               e.printStackTrace();
           }
       }

       public static void viewAttributes5(Path path){
           try {
               Map<String, Object> attrMap = Files.readAttributes(path, "dos:*"); //gets a Map
           } catch (IOException e){
               e.printStackTrace();
           }
       }

    }

Summary

We have learned how to read file attributes in Java NIO using 5 different ways. To provide a rough comparison (only applicable to the Dos variants) between the 5 ways, you can refer to the picture below.

NIO_Comparison.png

The full project code can be found here: https://github.com/dmitrilc/DaniwebJavaNioFileAttribute