Apache Commons FileUtils – File Operations

Introduction

I have already written various posts to work with Files and Directories. They are Java NIO FilesNIO Files operating on directories, and Apache Commons IOUtils. On similar lines, this post is on Apache Commons FileUtils class to work on Files. I will write a separate post to cover directory manipulations using FileUtils.

Apache Commons IO FileUtils

Apache Commons FileUtils is a class that has many utility methods for file and directory manipulation. This post covers the following file manipulations:

  • Reading files
  • Writing files
  • Copying files
  • Moving files
  • Check if a file is newer or older than a file/date
  • Deleting files

For this post, I will mostly use a file called sample-file.txt which has the below data in it.

1-Will-90
2-James-87
3-Kyle-67

Importing Apache Commons IO FileUtils

The FileUtils class is part of Apache Commons IO library. You can import it for Maven projects as:

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.7</version>
</dependency>

You can find the latest version of commons-io from Maven.

Reading files using FileUtils

Now we will learn how to read file contents using Apache Commons FileUtils.

readLines

The readLines method reads the file contents and returns a list of string. Each string is a line in the file. The readLines method takes a File object and the charset to use.

File file = new File("/Users/JavaDevCentral/data/sample-file.txt");
List<String> lines = FileUtils.readLines(file, StandardCharsets.UTF_8);
System.out.println(lines);

This prints,

[1-Will-90, 2-James-87, 3-Kyle-67]

readFileToString

To read the entire file content as a String, use the readFileToString method.

String fileAsString = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
System.out.println(fileAsString);

This outputs,

1-Will-90
2-James-87
3-Kyle-67

readFileToByteArray

Alternatively, to read a file as a byte array, use readFileToByteArray.

byte[] fileAsByteArray = FileUtils.readFileToByteArray(file);
System.out.println(new String(fileAsByteArray));

Writing files

We will learn about four methods to deal with writing files

  • write
  • writeLines
  • writeStringToFile
  • writeByteArrayToFile

FileUtils.write method

The write method writes a CharSequence to a given file (It creates the file if does not exist). It also creates all directories if they do not already exist.

File file = new File("/Users/JavaDevCentral/data/output-file.txt"); String data = "some-data"; //creates top level directories as well (if they do not exist) FileUtils.write(file, dataToBeWritten, StandardCharsets.UTF_8);

The above code will write the string ‘some-data’ into the target file.

An overload of the write method accepts a flag called append. If it is set to true, it appends the data to the file; else it overwrites.

FileUtils.write(file, System.lineSeparator() + data, StandardCharsets.UTF_8, true);

Now, the destination file has the below shown data in it.

some-data
some-data

FileUtils.writeLines method

There is lots of variation (overloads) of the writeLines method. But they are simple to understand. First, at the simplest, we pass a Collection<?> and a file. It writes the toString() representation of each object in the list in the file (one in each line).

List<String> linesToBeWritten = new ArrayList<>();
linesToBeWritten.add("line1");
linesToBeWritten.add("line2");
linesToBeWritten.add("line3");

FileUtils.writeLines(file, linesToBeWritten);

Now, the file has the below content in it.

line1
line2
line3

By default, it overwrites the file contents (if not empty). To append, pass a boolean value (true) to the writeLines method.

FileUtils.writeLines(file, linesToBeWritten, true);

Second, we can pass a line ending String to the writeLines method. By default, it uses the System default line ending. 

FileUtils.writeLines(file, linesToBeWritten, "~");
FileUtils.writeLines(file, linesToBeWritten, "~", true);

The above code uses the tilde character as the line terminator. The second call passes the append flag as true.

Resulting file content after executing the above code is:
line1~line2~line3~line1~line2~line3~

Finally, we can pass a charset as a parameter to all the variations of writeLines method we have seen so far.

FileUtils.writeLines(file, "UTF-8", linesToBeWritten);
FileUtils.writeLines(file, "UTF-8",linesToBeWritten, true);

FileUtils.writeLines(file, "UTF-8", linesToBeWritten, "~");
FileUtils.writeLines(file, "UTF-8", linesToBeWritten, "~", true);

writeStringToFile

The writeStringToFile method writes a String to a file. It has an overload to control whether or not to append the data to the file (as always, the default is to overwrite).

FileUtils.writeStringToFile(file, dataToBeWritten, StandardCharsets.UTF_8);
FileUtils.writeStringToFile(file, System.lineSeparator() + dataToBeWritten, 
        StandardCharsets.UTF_8, true);

writeByteArrayToFile

The writeByteArrayToFile is similar to writeStringToFile but works for a byte[].

byte[] bytesToBeWritten = dataToBeWritten.getBytes(StandardCharsets.UTF_8);
FileUtils.writeByteArrayToFile(file, bytesToBeWritten);
FileUtils.writeByteArrayToFile(file, bytesToBeWritten, true);

It has two other overloads where we can control the offset and length. The offset parameter specifies the starting offset from which to write and the length parameter tells how many bytes to write.

String dataToBeWritten = "some-data";
FileUtils.writeByteArrayToFile(file, bytesToBeWritten, 0, 4); //Writes ‘some’ into the file

//Writes '-data' into the file (appends it)
FileUtils.writeByteArrayToFile(file, bytesToBeWritten, 4, 5, true);

It throws an IndexOutOfBoundsException when the passed offset and length are not valid. Example, when we pass a length that is more than the length of the byte[].

FileUtils.writeByteArrayToFile(file, bytesToBeWritten, 4, 11, true);

Copying files

This section covers copying files from one location to another.

CopyFile

The FileUtils.copyFile method copies a given file to a new location identified by the destination file object. It creates the destination directory and (optionally) all the parent directories if they do not exit. If the destination file already exits, the copy operation will overwrite it.

This operation tries to preserve the file’s last modified date but is not guaranteed.

File sourceFile = new File("/Users/JavaDevCentral/data/sample-file.txt");
File destinationFile = new File("/Users/JavaDevCentral/data/output-file.txt");

FileUtils.copyFile(sourceFile, destinationFile);

This will create a file named output-file.txt and the contents of the sample-file.txt will be written into it.

If we copy it to a destination path like /Users/JavaDevCentral/path1/path2/output-file.txt, it will create the path1 and path2 directories.

Other overloaded FileUtils.copyFile methods

There is an overloaded copyFile method which accepts a flag to preserveFileDate. When it is set to true, it tries to preserve the last modified date of the copied file same as the source. But this is not guaranteed.

FileUtils.copyFile(sourceFile, destinationFile, true);

There is another overloaded copyFile which accepts an OutputStream as the destination.

OutputStream fileOutputStream = new FileOutputStream(destinationFile);
FileUtils.copyFile(sourceFile, fileOutputStream);

We created a FileOutputStream from the destination file and passed it to the copyFile method.

When source or destination is a directory

When the source or the destination file passed is a directory, then it fails by throwing an IOException.

//Throws java.io.IOException: Source '/Users/JavaDevCentral/data' exists but is a directory
sourceFile = new File("/Users/JavaDevCentral/data");
FileUtils.copyFile(sourceFile, destinationFile);


//Throws java.io.IOException: Destination '/Users/JavaDevCentral/data' exists but is a directory
destinationFile = new File("/Users/JavaDevCentral/data");
FileUtils.copyFile(sourceFile, destinationFile);

copyFileToDirectory method

This method copies the contents of the source file to a file in the specified destination directory (creating a new file in the destination with the same name as the source). It creates the destination directory (and all the parent directories) if they do not exist. If the destination file exists, it overwrites it.Like the copyFile method, it tries to preserve the last modified time.

File sourceFile = new File("/Users/JavaDevCentral/data/sample-file.txt");
destinationFile = new File("/Users/JavaDevCentral/data/path1/path2");
FileUtils.copyFileToDirectory(sourceFile, destinationFile);

This will create a new file named sample-file.txt in the directory path path1/path2. If they do not exist, it will create the all the folders. 

Similar to the copyFile, there is an overloaded method where we can pass a flag to preserve the last modified date (but not guaranteed to succeed).

FileUtils.copyFileToDirectory(sourceFile, destinationFile, true);

The difference between copyFile and copyFileToDirectory is copyFile allows us to specify the target file name which can be different from the source whereas we use copyFileToDirectory when we want to create a file in the destination with the same name as the source. Hence if the source and destination directory are the same, it will throw a IOException.

/* 
 Throws java.io.IOException:
 Source '/Users/JavaDevCentral/data/sample-file.txt' and 
 destination '/Users/JavaDevCentral/data/sample-file.txt' are the same
*/
File sourceFile = new File("/Users/JavaDevCentral/data/sample-file.txt");
destinationFile = new File("/Users/JavaDevCentral/data");
FileUtils.copyFileToDirectory(sourceFile, destinationFile);

FileUtils.copyInputStreamToFile

Using this, we can copy an inputstream to a destination file.

File sourceFile = new File("/Users/JavaDevCentral/data/sample-file.txt");
File destinationFile = new File("/Users/JavaDevCentral/data/output-file.txt");
InputStream fileInputStream = new FileInputStream(sourceFile);
FileUtils.copyInputStreamToFile(fileInputStream, destinationFile);

Moving files

moveFile

The FileUtils.moveFile method moves a file from the source to a destination.

File sourceFile = new File("/Users/JavaDevCentral/data/sample-file-copy.txt");
File destinationFile = new File("/Users/JavaDevCentral/data/moved-sample-file-copy.txt");

FileUtils.moveFile(sourceFile, destinationFile);

This will move the file ‘sample-file-copy.txt’ as ‘moved-sample-file-copy.txt’.

moveFileToDirectory

The moveFileToDirectory moves a file into the specified directory. Hence, the moved file will have the same name as the source file being moved. It accepts a boolean called createDestDir which if set to true will create the destination directory (including all parent directories).

File destinationDir = new File("/Users/JavaDevCentral/path1/path2");
FileUtils.moveFileToDirectory(sourceFile, destinationDir, true);

If we set createDestDir to false and if the target directory does not exist, it throws a java.io.FileNotFoundException.

/*
  Throws java.io.FileNotFoundException: Destination directory '/Users/JavaDevCentral/path1
  /path2' does not exist [createDestDir=false]
*/

File destinationDir = new File("/Users/JavaDevCentral/path1/path2");
FileUtils.moveFileToDirectory(sourceFile, destinationDir, false);

If a file with the same name is already present in the destination, the move will fail with an org.apache.commons.io.FileExistsException.

Is File newer or older

The Apache Commons FileUtils class has two methods with which we can check if a file is newer or older, comparing it to a date or another file or a time represented in milliseconds.

FileUtils.isFileNewer

File file1 = new File("/Users/JavaDevCentral/data/sample-file.txt");
File file2 = new File("/Users/JavaDevCentral/data/output-file.txt");
Calendar calendar = Calendar.getInstance();
calendar.set(2020, Calendar.MAY, 1);
System.out.println(FileUtils.isFileNewer(file1, calendar.getTime()));

The above code checks if the file file1 is newer than May 1, 2020. If yes, it will print true else it will print false

To compare a file against another, we can pass both the file references to the isFileNewer method. The below code tests if file1 is newer than file2 and the second call checks the other way around.
System.out.println(FileUtils.isFileNewer(file1, file2));
System.out.println(FileUtils.isFileNewer(file2, file1));

The last version allows us to pass a long timestamp to compare a file with.

System.out.println(FileUtils.isFileNewer(file2, System.currentTimeMillis()));

FileUtils.isFileOlder

This is the inverse of isFileNewer method. It checks if the specified file is older than a specified Date/file/timestamp (a long value).

System.out.println(FileUtils.isFileOlder(file1, calendar.getTime()));

System.out.println(FileUtils.isFileOlder(file1, file2));
System.out.println(FileUtils.isFileOlder(file2, file1));

System.out.println(FileUtils.isFileOlder(file2, System.currentTimeMillis()));

Deleting files

Now we will see how to delete files using Apache Commons FileUtils.

deleteQuietly

The deleteQuietly method deletes a file but never throws any exception. It returns true if the file deletion was successful. If the file does not exist, it returns false (but throws no exceptions).

File file = new File("/Users/JavaDevCentral/data/file.txt");
System.out.println(FileUtils.deleteQuietly(file));

forceDelete

The forceDelete method deletes a file but throws exception when the file could not be deleted.

FileUtils.forceDelete(file);

If the file to be deleted does not exist, it throws a java.io.FileNotFoundException.

forceDeleteOnExit

The forceDeleteOnExit is a useful method to automatically delete a file when the JVM exits.

FileUtils.forceDeleteOnExit(file);

Conclusion

This post covered the Apache Commons FileUtils files operations or files manipulation. We learnt how to read a file, write data to a file. Also, we saw how to copy and move a file, checking a file is newer or older. Finally, we saw how to delete a file using FileUtils. 
Apache commons offer many useful libraries. To learn more about them, see here.

References

Leave a Reply