Java NIO Files
Jakob Jenkov |
The Java NIO Files
class (java.nio.file.Files
) provides several methods for manipulating
files in the file system. This Java NIO Files
tutorial will cover the most commonly used of these
methods. The Files
class contains many methods, so check the JavaDoc too, if you need a method that
is not described here. The Files
class just might have a method for it still.
The java.nio.file.Files
class works with java.nio.file.Path
instances, so you need to understand the Path
class before you can work with the Files
class.
Files.exists()
The Files.exists()
method checks if a given Path
exists in the file system.
It is possible to create Path
instances that do not exist in the file system. For instance, if you plan
to create a new directory, you would first create the corresponding Path
instance, and then create
the directory.
Since Path
instances may or may not point to paths that exist in the file system,
you can use the Files.exists()
method to determine if they do (in case you need to check that).
Here is a Java Files.exists()
example:
Path path = Paths.get("data/logging.properties"); boolean pathExists = Files.exists(path, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});
This example first creates a Path
instance pointing to the path we want to check if exists or not.
Second, the example calls the Files.exists()
method with the Path
instance as the
first parameter.
Notice the second parameter of the Files.exists()
method. This parameter is an array of options
that influence how the Files.exists()
determines if the path exists or not. In this example above
the array contains the LinkOption.NOFOLLOW_LINKS
which means that the Files.exists()
method should not follow symbolic links in the file system to determine if the path exists.
Files.createDirectory()
The Files.createDirectory()
method creates a new directory from a Path
instance.
Here is a Java Files.createDirectory()
example:
Path path = Paths.get("data/subdir"); try { Path newDir = Files.createDirectory(path); } catch(FileAlreadyExistsException e){ // the directory already exists. } catch (IOException e) { //something else went wrong e.printStackTrace(); }
The first line creates the Path
instance that represents the directory to create.
Inside the try-catch
block the Files.createDirectory()
method is called with the path
as parameter. If creating the directory succeeds, a Path
instance is returned which points to the
newly created path.
If the directory already exists, a java.nio.file.FileAlreadyExistsException
will
be thrown. If something else goes wrong, an IOException
may get thrown. For instance, if the
parent directory of the desired, new directory does not exist, an IOException
may get thrown.
The parent directory is the directory in which you want to create the new directory. Thus, it means the parent
directory of the new directory.
Files.copy()
The Files.copy()
method copies a file from one path to another. Here is a Java NIO Files.copy()
example:
Path sourcePath = Paths.get("data/logging.properties"); Path destinationPath = Paths.get("data/logging-copy.properties"); try { Files.copy(sourcePath, destinationPath); } catch(FileAlreadyExistsException e) { //destination file already exists } catch (IOException e) { //something else went wrong e.printStackTrace(); }
First the example creates a source and destination Path
instance. Then the example calls
Files.copy()
, passing the two Path
instances as parameters. This will result in the
file referenced by the source path to be copied to the file referenced by the destination path.
If the destination file already exists, a java.nio.file.FileAlreadyExistsException
is thrown.
If something else goes wrong, an IOException
will be thrown. For instance, if the directory to
copy the file to does not exist, an IOException
will be thrown.
Overwriting Existing Files
It is possible to force the Files.copy()
to overwrite an existing file. Here an example showing
how to overwrite an existing file using Files.copy()
:
Path sourcePath = Paths.get("data/logging.properties"); Path destinationPath = Paths.get("data/logging-copy.properties"); try { Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING); } catch(FileAlreadyExistsException e) { //destination file already exists } catch (IOException e) { //something else went wrong e.printStackTrace(); }
Notice the third parameter to the Files.copy()
method. This parameter instructs the copy()
method to overwrite an existing file if the destination file already exists.
Files.move()
The Java NIO Files
class also contains a function for moving files from one path to another. Moving
a file is the same as renaming it, except moving a file can both move it to a different directory and change its
name in the same operation. Yes, the java.io.File
class could also do that with its renameTo()
method, but now you have the file move functionality in the java.nio.file.Files
class too.
Here is a Java Files.move()
example:
Path sourcePath = Paths.get("data/logging-copy.properties"); Path destinationPath = Paths.get("data/subdir/logging-moved.properties"); try { Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { //moving file failed. e.printStackTrace(); }
First the source path and destination path are created. The source path points to the file to move, and
the destination path points to where the file should be moved to. Then the Files.move()
method is
called. This results in the file being moved.
Notice the third parameter passed to Files.move()
.
This parameter tells the Files.move()
method to overwrite any existing file at the destination
path. This parameter is actually optional.
The Files.move()
method may throw an IOException
if moving the file fails. For instance,
if a file already exists at the destination path, and you have left out the StandardCopyOption.REPLACE_EXISTING
option, or if the file to move does not exist etc.
Files.delete()
The Files.delete()
method can delete a file or directory. Here is a Java Files.delete()
example:
Path path = Paths.get("data/subdir/logging-moved.properties"); try { Files.delete(path); } catch (IOException e) { //deleting file failed e.printStackTrace(); }
First the Path
pointing to the file to delete is created. Second the Files.delete()
method is called. If the Files.delete()
fails to delete the file for some reason (e.g. the file
or directory does not exist), an IOException
is thrown.
Files.walkFileTree()
The Files.walkFileTree()
method contains functionality for traversing a directory tree recursively.
The walkFileTree()
method takes a Path
instance and a FileVisitor
as
parameters. The Path
instance points to the directory you want to traverse. The FileVisitor
is called during traversion.
Before I explain how the traversal works, here is first the FileVisitor
interface:
public interface FileVisitor { public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs) throws IOException; public FileVisitResult visitFile( Path file, BasicFileAttributes attrs) throws IOException; public FileVisitResult visitFileFailed( Path file, IOException exc) throws IOException; public FileVisitResult postVisitDirectory( Path dir, IOException exc) throws IOException { }
You have to implement the FileVisitor
interface yourself, and pass an instance of your implementation
to the walkFileTree()
method. Each method of your FileVisitor
implementation will get
called at different times during the directory traversal. If you do not need to hook into all of these methods,
you can extend the SimpleFileVisitor
class, which contains default implementations of all methods
in the FileVisitor
interface.
Here is a walkFileTree()
example:
Files.walkFileTree(path, new FileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println("pre visit dir:" + dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("visit file: " + file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { System.out.println("visit file failed: " + file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { System.out.println("post visit directory: " + dir); return FileVisitResult.CONTINUE; } });
Each of the methods in the FileVisitor
implementation gets called at different times during
traversal:
The preVisitDirectory()
method is called just before visiting any directory. The
postVisitDirectory()
method is called just after visiting a directory.
The visitFile()
mehtod is called for every file visited during the file walk. It is not called
for directories - only files. The visitFileFailed()
method is called in case visiting a file fails.
For instance, if you do not have the right permissions, or something else goes wrong.
Each of the four methods return a FileVisitResult
enum instance. The FileVisitResult
enum contains the following four options:
CONTINUE
TERMINATE
SKIP_SIBLINGS
SKIP_SUBTREE
By returning one of these values the called method can decide how the file walk should continue.
CONTINUE
means that the file walk should continue as normal.
TERMINATE
means that the file walk should terminate now.
SKIP_SIBLINGS
means that the file walk should continue but without visiting any siblings of this
file or directory.
SKIP_SUBTREE
means that the file walk should continue but without visiting the entries in this
directory. This value only has a function if returned from preVisitDirectory()
. If returned from any
other methods it will be interpreted as a CONTINUE
.
Searching For Files
Here is a walkFileTree()
that extends SimpleFileVisitor
to look for a file named
README.txt
:
Path rootPath = Paths.get("data"); String fileToFind = File.separator + "README.txt"; try { Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String fileString = file.toAbsolutePath().toString(); //System.out.println("pathString = " + fileString); if(fileString.endsWith(fileToFind)){ System.out.println("file found at path: " + file.toAbsolutePath()); return FileVisitResult.TERMINATE; } return FileVisitResult.CONTINUE; } }); } catch(IOException e){ e.printStackTrace(); }
Deleting Directories Recursively
The Files.walkFileTree()
can also be used to delete a directory with all files and subdirectories
inside it. The Files.delete()
method will only delete a directory if it is empty. By walking through
all directories and deleting all files (inside visitFile()
) in each directory, and afterwards delete
the directory itself (inside postVisitDirectory()
) you can delete a directory with all
subdirectories and files. Here is a recursive directory deletion example:
Path rootPath = Paths.get("data/to-delete"); try { Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("delete file: " + file.toString()); Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.delete(dir); System.out.println("delete dir: " + dir.toString()); return FileVisitResult.CONTINUE; } }); } catch(IOException e){ e.printStackTrace(); }
Additional Methods in the Files Class
The java.nio.file.Files
class contains many other useful functions, like functions for creating
symbolic links, determining the file size, setting file permissions etc. Check out the JavaDoc for the
java.nio.file.Files
class for more information about these methods.
Tweet | |
Jakob Jenkov |