Chapter 14 I/O Notes Flashcards
Referencing Files and Directories
- I/O - java.io.File class
- NIO.2 - java.nio.file.Path interface.
Conceptualizing the File System
* file
* directory
* file system
* root directory
* path
* file separators
* absolute path
* relative path
* path symbol
* symbolic link
- A
file
within the storage device holds data. Files are organized into hierarchies using directories. - A
directory
is a location that can contain files as well as other directories. - The
file system
is in charge of reading and writing data within a computer. Different operating systems use different file systems to manage their data. -
root directory
is the topmost directory in the file system, ex: Windows C:\ and Linux / - A
path
is a representation of a file or directory within a file system. -
File Separators
, Unix-based systems use the forward slash, /, for paths, whereas Windows-based systems use the backslash, \ - The
absolute path
of a file or directory is the full path from the root directory to the file or directory, - the
relative path
of a file or directory is the path from the current working directory to the file or directory. - A
path symbol
is one of a reserved series of characters with special meaning in some file systems.- . A reference to the current directory
- .. A reference to the parent of the current directory
- A
symbolic link
is a special file within a file system that serves as a reference or pointer to another file or directory.
- I/O APIs do not support symbolic links,
- NIO.2 includes full support for creating, detecting, and navigating symbolic links within the file system.
I/O APIs do not support symbolic links
Operating System File Separators
Java offers a system property to retrieve the local separator character for the current environment:
System.out.print(System.getProperty(“file.separator”));
Creating a File or Path
-
I/O, this is the
java.io.File class
-
NIO.2, it is the
java.nio.file.Path interface
.
Creating a File
File zooFile1 = new File("/home/tiger/data/stripes.txt"); File zooFile2 = new File("/home/tiger", "data/stripes.txt"); File parent = new File("/home/tiger"); File zooFile3 = new File(parent, "data/stripes.txt"); System.out.println(zooFile1.exists());
The File class
is created by calling its constructor
.
This code shows three different constructors:
~~~
File zooFile1 = new File(“/home/tiger/data/stripes.txt”);
File zooFile2 = new File(“/home/tiger”, “data/stripes.txt”);
File parent = new File(“/home/tiger”);
File zooFile3 = new File(parent, “data/stripes.txt”);
System.out.println(zooFile1.exists());
~~~
All three create a File object that points to the same location on disk.
If we passed null as the parent to the final constructor, it would be ignored, and the method would behave the same way as the single String constructor.
For fun, we also show how to tell if the file exists on the file system.
Creating a Path
//Path static method of() Path zooPath1 = Path.of("/home/tiger/data/stripes.txt"); Path zooPath2 = Path.of("/home", "tiger", "data", "stripes.txt"); //Paths factory class static method get() Path zooPath3 = Paths.get("/home/tiger/data/stripes.txt"); Path zooPath4 = Paths.get("/home", "tiger", "data", "stripes.txt"); System.out.println(Files.exists(zooPath1));
- Since Path is an interface, we can’t create an instance directly. After all, interfaces don’t have constructors!
- obtain a Path object is to use a static factory method defined on Path or Paths.
All four of these examples point to the same reference on disk:
~~~
//Path static method of()
Path zooPath1 = Path.of(“/home/tiger/data/stripes.txt”);
Path zooPath2 = Path.of(“/home”, “tiger”, “data”, “stripes.txt”);
//Paths factory class static method get()
Path zooPath3 = Paths.get(“/home/tiger/data/stripes.txt”);
Path zooPath4 = Paths.get(“/home”, “tiger”, “data”, “stripes.txt”);
System.out.println(Files.exists(zooPath1));
~~~
Both methods allow passing a varargs parameter to pass additional path elements. The values are combined and automatically separated by the operating system–dependent file separator. We also show the Files helper class, which can check if the file exists on the file system.
NOTE
> [!NOTE]
both the I/O and NIO.2 classes can interact with a URI.
A uniform resource identifier (URI) is a string of characters that identifies a resource.
It begins with a schema that indicates the resource type, followed by a path value such as file:// for local file systems and http://, https://, and ftp:// for remote file systems.
- both the I/O and NIO.2 classes can interact with a URI.
- A uniform resource identifier (URI) is a string of characters that identifies a resource.
Switching between File and Path
When working with newer applications, you should rely on NIO.2’s Path interface, as it contains a lot more features.
File file = new File("rabbit"); Path nowPath = file.toPath(); File backToFile = nowPath.toFile();
Obtaining a Path from the FileSystems
Class
- The FileSystems class creates instances of the abstract FileSystem class.
- The latter includes methods for working with the file system directly.
- Both Paths.get() and Path.of() are shortcuts for this FileSystem method.
Path zooPath1 = FileSystems.getDefault().getPath("/home/tiger/data/stripes.txt"); Path zooPath2 = FileSystems.getDefault().getPath("/home", "tiger", "data", "stripes.txt");
Reviewing I/O and NIO.2 Relationships
FIGURE 14.3 I/O and NIO.2 class and interface relationships
* FileSystems create FileSystem
* FileSystem create Path
* Paths create Path
* Files uses Path
* Path covert java.net.URI
* Path covert java.io.File
NOTE
> [!NOTE]
The java.io.File is the I/O class,
while Files is an NIO.2 helper class.
Files operates on Path instances, not java.io.File instances.
- java.io.File
- java.io.nio.file.Files NIO.2 helper class
- Files operates on Path instances
TABLE 14.2 Options for creating File and Path
java.io.File
* public File(String pathname)
* public File(File parent, String child)
* public File(String parent, String child)
* public Path toPath()
java.nio.file.Path
* public default File toFile()
* public static Path of(String first, String… more)
* public static Path of(URI uri)
java.nio.file.Paths
* public static Path get(String first, String… more)
* public static Path get(URI uri)
java.nio.file.FileSystem
* public Path getPath(String first, String… more)
java.nio.file.FileSystems
* public static FileSystem getDefault()
Operating on File and Path
Answer
Using Shared Functionality
TABLE 14.3 Common File
and Path
operations
* Gets name of file/directory
* getName()
* getFileName()
* Retrieves parent directory or null if there is none
* getParent()
* getParent()
* Checks if file/directory is absolute path
* isAbsolute()
* isAbsolute()
TABLE 14.4 Common File
and Files
operations
* Deletes file/directory
* delete()
* deleteIfExists(Path p) throws IOException
* Checks if file/directory exists
* exists()
* exists(Path p, LinkOption… o)
* Retrieves absolute path of file/directory
* getAbsolutePath()
* toAbsolutePath()
* Checks if resource is directory
* isDirectory()
* isDirectory(Path p, LinkOption… o)
* Checks if resource is file
* isFile()
* isRegularFile(Path p, LinkOption… o)
* Returns the time the file was last modified
* lastModified()
* getLastModifiedTime(Path p, LinkOption… o) throws IOException
* Retrieves number of bytes in file
* length()
* size(Path p) throws IOException
* Lists contents of directory
* listFiles()
* list(Path p) throws IOException
* Creates directory
* mkdir()
* createDirectory(Path p, FileAttribute… a) throws IOException
* Creates directory including any nonexistent parent directories
* mkdirs()
* createDirectories(Path p, FileAttribute… a) throws IOException
* Renames file/directory denoted
* renameTo(File dest)
* move(Path src, Path dest, CopyOption… o) throws IOException
TABLE 14.3 Common File
and Path
operations
TABLE 14.3 Common File
and Path
operations
* Gets name of file/directory
* getName()
* getFileName()
* Retrieves parent directory or null if there is none
* getParent()
* getParent()
* Checks if file/directory is absolute path
* isAbsolute()
* isAbsolute()
TABLE 14.4 Common File
and Files
operations
TABLE 14.4 Common File
and Files
operations
* Deletes file/directory
* delete()
* deleteIfExists(Path p) throws IOException
* Checks if file/directory exists
* exists()
* exists(Path p, LinkOption… o)
* Retrieves absolute path of file/directory
* getAbsolutePath()
* toAbsolutePath() <–this is Path interface method
* Checks if resource is directory
* isDirectory()
* isDirectory(Path p, LinkOption… o)
* Checks if resource is file
* isFile()
* isRegularFile(Path p, LinkOption… o)
* Returns the time the file was last modified
* lastModified()
* getLastModifiedTime(Path p, LinkOption… o) throws IOException
* Retrieves number of bytes in file
* length()
* size(Path p) throws IOException
* Lists contents of directory
* listFiles()
* list(Path p) throws IOException
* Creates directory
* mkdir()
* createDirectory(Path p, FileAttribute… a) throws IOException
* Creates directory including any nonexistent parent directories
* mkdirs()
* createDirectories(Path p, FileAttribute… a) throws IOException
* Renames file/directory denoted
* renameTo(File dest)
* move(Path src, Path dest, CopyOption… o) throws IOException
I/O API example:
10: public static void io() { 11: var file = new File("C:\\data\\zoo.txt"); 12: if (file.exists()) { 13: System.out.println("Absolute Path: " + file.getAbsolutePath()); 14: System.out.println("Is Directory: " + file.isDirectory()); 15: System.out.println("Parent Path: " + file.getParent()); 16: if (file.isFile()) { 17: System.out.println("Size: " + file.length()); 18: System.out.println("Last Modified: " + file.lastModified()); 19: } else { 20: for (File subfile : file.listFiles()) { 21: System.out.println(" " + subfile.getName()); 22: } } } }
If the path provided points to a valid file, the program outputs something similar to the following due to the if statement on line 16:
~~~
Absolute Path: C:\data\zoo.txt
Is Directory: false
Parent Path: C:\data
Size: 12382
Last Modified: 1650610000000
~~~
if the path provided points to a valid directory, such as C:\data, the program outputs something similar to the following, thanks to the else block:
~~~
Absolute Path: C:\data
Is Directory: true
Parent Path: C:\
employees.txt
zoo.txt
zoo-backup.txt
~~~
NOTE
> [!NOTE]
we used two backslashes (\\)
in the path String, such as C:\data\zoo.txt.
When the compiler sees a \\
inside a String expression, it interprets it as a single \
value.
compiler sees a \\
inside a String expression, it interprets it as a single \
value.
NIO.2 example:
~~~
25: public static void nio() throws IOException {
26: var path = Path.of(“C:\data\zoo.txt”);
27: if (Files.exists(path)) {
28: System.out.println(“Absolute Path: “ + path.toAbsolutePath());
29: System.out.println(“Is Directory: “ + Files.isDirectory(path));
30: System.out.println(“Parent Path: “ + path.getParent());
31: if (Files.isRegularFile(path)) {
32: System.out.println(“Size: “ + Files.size(path));
33: System.out.println(“Last Modified: “
34: + Files.getLastModifiedTime(path));
35: } else {
36: try (Stream<Path> stream = Files.list(path)) {
37: stream.forEach(p ->
38: System.out.println(" " + p.getName()));
39: } } } }
~~~</Path>
More APIs in NIO.2 throw IOException than the I/O APIs did. In this case, Files.size(), Files.getLastModifiedTime(), and Files.list() throw an IOException.
Second, lines 36–39 use a Stream and a lambda instead of a loop. Since streams use lazy evaluation, this means the method will load each path element as needed, rather than the entire directory at once.
Closing the Stream
Stream object inside a try-with-resources?
~~~
36: try (Stream<Path> stream = Files.list(path)) {
37: stream.forEach(p ->
38: System.out.println(" " + p.getName()));
39: }
~~~</Path>
- The NIO.2 stream-based methods open a connection to the file system that must be properly closed;
- otherwise, a resource leak could ensue. A resource leak within the file system means the path may be locked from modification long after the process that used it is completed.
Handling Methods That Declare IOException
Many of the methods presented in this chapter declare IOException. Common causes of a method throwing this exception include the following:
* Loss of communication to the underlying file system.
* File or directory exists but cannot be accessed or modified.
* File exists but cannot be overwritten.
* File or directory is required but does not exist.
Methods that access or change files and directories, such as those in the Files class, often declare IOException. There are exceptions to this rule, as we will see. For example, the method Files.exists() does not declare IOException. If it did throw an exception when the file did not exist, it would never be able to return false! As a rule of thumb, if a NIO.2 method declares an IOException, it usually requires the paths it operates on to exist.
Providing NIO.2 Optional Parameters
TABLE 14.5 Common NIO.2 method arguments
-
LinkOption.NOFOLLOW_LINKS
-Do not follow symbolic links. -
StandardCopyOption.ATOMIC_MOVE
- Move file as atomic file system operation. -
StandardCopyOption.COPY_ATTRIBUTES
-Copy existing attributes to new file. -
StandardCopyOption.REPLACE_EXISTING
-Overwrite file if it already exists. -
StandardOpenOption.APPEND
-If file is already open for write, append to the end. -
StandardOpenOption.CREATE
-Create new file if it does not exist. -
StandardOpenOption.CREATE_NEW
-Create new file only if it does not exist; fail otherwise. -
StandardOpenOption.READ
-Open for read access. -
StandardOpenOption.TRUNCATE_EXISTING
-If file is already open for write, erase file and append to beginning. -
StandardOpenOption.WRITE
-Open for write access. -
FileVisitOption.FOLLOW_LINKS
-Follow symbolic links.
what the following call to Files.exists() with the LinkOption does in the following code snippet?
Path path = Paths.get("schedule.xml"); boolean exists = Files.exists(path, LinkOption.NOFOLLOW_LINKS);
- The Files.exists() simply checks whether a file exists.
- But if the parameter is a symbolic link, the method checks whether the target of the symbolic link exists, instead.
- Providing
LinkOption.NOFOLLOW_LINKS
means the default behavior will be overridden, and the method will check whether the symbolic link itself exists.
For example, the Files.move() method takes a CopyOption vararg so it can take enums of different types, and more options can be added over time.
public static Path copy(Path source, Path target, CopyOption... options) throws IOException
LinkOption and StandardCopyOption Implemented CopyOption
void copy(Path source, Path target) throws IOException { Files.move(source, target, LinkOption.NOFOLLOW_LINKS, StandardCopyOption.ATOMIC_MOVE); }
Answer
Interacting with NIO.2 Paths
Path
instances are immutable
.
In the following example, the Path operation on the second line is lost since p is immutable:
~~~
Path p = Path.of(“whale”);
p.resolve(“krill”);
System.out.println(p); // whale
~~~
Many of the methods available in the Path interface transform the path value in some way and return a new Path object, allowing the methods to be chained. We demonstrate chaining in the following example, the details of which we discuss in this section of the chapter:
~~~
Path.of(“/zoo/../home”).getParent().normalize().toAbsolutePath();
~~~
Viewing the Path
String toString()
int getNameCount()
Path getName(int index)
The Path interface contains three methods to retrieve basic information about the path representation.
The toString()
method returns a String representation of the entire path. In fact, it is the only method in the Path interface to return a String.
The getNameCount()
and getName()
methods are often used together to retrieve the number of elements in the path and a reference to each element, respectively. These two methods do not include the root directory as part of the path.
Path path = Paths.get("/land/hippo/harry.happy"); System.out.println("The Path Name is: " + path); for(int i=0; i<path.getNameCount(); i++) System.out.println(" Element " + i + " is: " + path.getName(i));
The code prints the following:
~~~
The Path Name is: /land/hippo/harry.happy
Element 0 is: land
Element 1 is: hippo
Element 2 is: harry.happy
~~~
The getNameCount()
and getName()
methods do not consider the root part of the path.
~~~
var p = Path.of(“/”);
System.out.print(p.getNameCount()); // 0
System.out.print(p.getName(0)); // IllegalArgumentException
~~~
Notice that if you try to call getName()
with an invalid index, it will throw an exception at runtime.
Creating Part of the Path
~~~
var p = Paths.get(“/mammal/omnivore/raccoon.image”);
System.out.println(“Path is: “ + p);
for (int i = 0; i < p.getNameCount(); i++) {
System.out.println(“ Element “ + i + “ is: “ + p.getName(i));
}
System.out.println();
System.out.println(“subpath(0,3): “ + p.subpath(0, 3));
System.out.println(“subpath(1,2): “ + p.subpath(1, 2));
System.out.println(“subpath(1,3): “ + p.subpath(1, 3));
~~~
The Path interface includes the subpath()
method to select portions of a path. It takes two parameters: an inclusive beginIndex and an exclusive endIndex.
The output of this code snippet is the following:
Path is: /mammal/omnivore/raccoon.image Element 0 is: mammal Element 1 is: omnivore Element 2 is: raccoon.image subpath(0,3): mammal/omnivore/raccoon.image subpath(1,2): omnivore subpath(1,3): omnivore/raccoon.image
Like getNameCount() and getName(), subpath() is zero-indexed and does not include the root. Also like getName(), subpath() throws an exception if invalid indices are provided.
~~~
var q = p.subpath(0, 4); // IllegalArgumentException
var x = p.subpath(1, 1); // IllegalArgumentException
~~~
The first example throws an exception at runtime, since the maximum index value allowed is 3. The second example throws an exception since the start and end indexes are the same, leading to an empty path value.
Accessing Path Elements
- The Path interface contains numerous methods for retrieving particular elements of a Path, returned as Path objects themselves.
- The
getFileName()
method returns the Path element of the current file or directory, - while
getParent()
returns the full path of the containing directory. - The getParent() method returns null if operated on the root path or at the top of a relative path.
- The getRoot() method returns the root element of the file within the file system, or null if the path is a relative path.
Consider the following method, which prints various Path elements:
public void printPathInformation(Path path) { System.out.println("Filename is: " + path.getFileName()); System.out.println(" Root is: " + path.getRoot()); Path currentParent = path; while((currentParent = currentParent.getParent()) != null) System.out.println(" Current parent is: " + currentParent); System.out.println(); }
The while loop in the printPathInformation() method continues until getParent() returns null. We apply this method to the following three paths:
printPathInformation(Path.of("zoo")); printPathInformation(Path.of("/zoo/armadillo/shells.txt")); printPathInformation(Path.of("./armadillo/../shells.txt"));
This sample application produces the following output:
Filename is: zoo Root is: null Filename is: shells.txt Root is: / Current parent is: /zoo/armadillo Current parent is: /zoo Current parent is: / Filename is: shells.txt Root is: null Current parent is: ./armadillo/.. Current parent is: ./armadillo Current parent is: .
Resolving Paths
resolve()
- The resolve() method provides overloaded versions that let you pass either a Path or String parameter.
- The object on which the resolve() method is invoked becomes the basis of the new Path object, with the input argument being appended onto the Path.
For the exam, you should be cognizant of
* mixing absolute and relative paths with the resolve() method.
* If an absolute path is provided as input to the method, that is the value returned.
* Simply put, you cannot combine two absolute paths using resolve().
apply resolve() to an absolute path and a relative path:
~~~
Path path1 = Path.of(“/cats/../panther”);
Path path2 = Path.of(“food”);
System.out.println(path1.resolve(path2));
~~~
The code snippet generates the following output:
/cats/../panther/food
what if it had been an absolute path?
Path path3 = Path.of("/turkey/food"); System.out.println(path3.resolve("/tiger/cage"));
Since the input parameter is an absolute path, the output would be the following:
/tiger/cage
For the exam, you should be cognizant of mixing absolute and relative paths with the resolve() method. If an absolute path is provided as input to the method, that is the value returned. Simply put, you cannot combine two absolute paths using resolve()
.
TIP
> [!TIP]
On the exam, when you see resolve()
, think concatenation.
On the exam, when you see resolve()
, think concatenation.
Relativizing a Path
relativize()
The Path interface includes a relativize() method for constructing the relative path from one Path to another, often using path symbols.
- If both path values are relative, the relativize() method computes the paths as if they are in the same current working directory.
- Alternatively, if both path values are absolute, the method computes the relative path from one absolute location to another, regardless of the current working directory.
- The relativize() method requires both paths to be absolute or relative and throws an exception if the types are mixed.
- On Windows-based systems, it also requires that if absolute paths are used, both paths must have the same root directory or drive letter
What do you think the following examples will print?
var path1 = Path.of("fish.txt"); var path2 = Path.of("friendly/birds.txt"); System.out.println(path1.relativize(path2)); System.out.println(path2.relativize(path1));
The examples print the following:
../friendly/birds.txt ../../fish.txt
The idea is this: if you are pointed at a path in the file system, what steps would you need to take to reach the other path? For example, to get to fish.txt from friendly/birds.txt, you need to go up two levels (the file itself counts as one level) and then select fish.txt.
The following example demonstrates this property when run on a Windows computer:
Path path3 = Paths.get("E:\\habitat"); Path path4 = Paths.get("E:\\sanctuary\\raven\\poe.txt"); System.out.println(path3.relativize(path4)); System.out.println(path4.relativize(path3));
This code snippet produces the following output:
..\sanctuary\raven\poe.txt ..\..\..\habitat
The relativize() method requires both paths to be absolute or relative and throws an exception if the types are mixed.
Path path1 = Paths.get("/primate/chimpanzee"); Path path2 = Paths.get("bananas.txt"); path1.relativize(path2); // IllegalArgumentException
On Windows-based systems, it also requires that if absolute paths are used, both paths must have the same root directory or drive letter. For example, the following would also throw an IllegalArgumentException on a Windows-based system:
Path path3 = Paths.get("C:\\primate\\chimpanzee"); Path path4 = Paths.get("D:\\storage\\bananas.txt"); path3.relativize(path4); // IllegalArgumentException
The relativize() method requires both paths to be absolute or relative and throws an exception if the types are mixed.
On Windows-based systems, it also requires that if absolute paths are used, both paths must have the same root directory or drive letter.
Normalizing a Path
Java provides the normalize() method to eliminate unnecessary redundancies in a path.
We can apply normalize() to some of our previous paths.
var p1 = Path.of("./armadillo/../shells.txt"); System.out.println(p1.normalize()); // shells.txt var p2 = Path.of("/cats/../panther/food"); System.out.println(p2.normalize()); // /panther/food var p3 = Path.of("../../fish.txt"); System.out.println(p3.normalize()); // ../../fish.txt
- The first two examples apply the path symbols to remove the redundancies,
- but what about the last one? That is as simplified as it can be.
- The
normalize()
method does not remove all of the path symbols, only the ones that can be reduced.
Consider the following example:
var p1 = Paths.get("/pony/../weather.txt"); var p2 = Paths.get("/weather.txt"); System.out.println(p1.equals(p2)); // false System.out.println(p1.normalize().equals(p2.normalize())); // true
The normalize()
method also allows us to compare equivalent paths.
The equals() method returns true if two paths represent the same value. In the first comparison, the path values are different. In the second comparison, the path values have both been reduced to the same normalized value, /weather.txt. This is the primary function of the normalize() method: to allow us to better compare different paths.
Retrieving the Real File System Path
toRealPath()
-
verify that the path exists within the file system using
toRealPath()
. - This method is similar to
normalize()
in that it eliminates any redundant path symbols. - It is also similar to
toAbsolutePath()
, in that it will join the path with the current working directory if the path is relative. - Unlike those two methods, though, toRealPath() will throw an exception if the path does not exist.
- In addition, it will follow symbolic links, with an optional LinkOption varargs parameter to ignore them.
Let’s say that we have a file system in which we have a symbolic link from /zebra to /horse.
What do you think the following will print, given a current working directory of /horse/schedule?
~~~
System.out.println(Paths.get(“/zebra/food.txt”).toRealPath());
System.out.println(Paths.get(“.././food.txt”).toRealPath());
~~~
The output of both lines is the following:
/horse/food.txt
In this example, the absolute and relative paths both resolve to the same absolute file, as the symbolic link points to a real file within the file system.
We can also use the toRealPath() method to gain access to the current working directory as a Path object.
System.out.println(Paths.get(".").toRealPath());
Reviewing NIO.2 Path APIs
TABLE 14.6 Path APIs
- File path as string - public String toString()
- Single segment - public Path getName(int index)
- Number of segments - public int getNameCount()
- Segments in range - public Path subpath(int beginIndex, int endIndex)
- Final segment - public Path getFileName()
- Immediate parent - public Path getParent()
- Top-level segment - public Path getRoot()
- Concatenate paths - public Path resolve(String p)
public Path resolve(Path p) - Construct path to one provided - public Path relativize(Path p)
- Remove redundant parts of path - public Path normalize()
- Follow symbolic links to find path on file system - public Path toRealPath()
Creating, Moving, and Deleting Files and Directories
Answer
Making Directories
public static Path createDirectory(Path dir, FileAttribute<?>… attrs) throws IOException public static Path createDirectories(Path dir, FileAttribute<?>… attrs) throws IOException
To create a directory, we use these Files methods:
public static Path createDirectory(Path dir, FileAttribute<?>… attrs) throws IOException public static Path createDirectories(Path dir, FileAttribute<?>… attrs) throws IOException
createDirectory()
* The createDirectory()
method will create a directory
* and throw an exception if it already exists or if the paths leading up to the directory do not exist.
createDirectories()
* The createDirectories()
method creates the target directory along with any nonexistent parent directories leading up to the path.
* If all of the directories already exist, createDirectories()
will simply complete without doing anything.
* This is useful in situations where you want to ensure a directory exists and create it if it does not.
Both of these methods also accept an optional list of FileAttribute<?>
values to apply to the newly created directory or directories.
The following shows how to create directories:
Files.createDirectory(Path.of("/bison/field")); Files.createDirectories(Path.of("/bison/field/pasture/green"));
- The first example creates a new directory, field, in the directory /bison, assuming /bison exists; otherwise, an exception is thrown.
- Contrast this with the second example, which creates the directory green along with any of the following parent directories if they do not already exist, including bison, field, and pasture.
Copying Files
public static Path copy(Path source, Path target, CopyOption… options) throws IOException
The Files class provides a method for copying files and directories within the file system.
public static Path copy(Path source, Path target, CopyOption… options) throws IOException
The method copies a file or directory from one location to another using Path objects.
A shallow copy means that the files and subdirectories within the directory are not copied.
A deep copy means that the entire tree is copied, including all of its content and subdirectories.
The following shows an example of copying a file and a directory:
~~~
Files.copy(Paths.get(“/panda/bamboo.txt”), Paths.get(“/panda-save/bamboo.txt”));
Files.copy(Paths.get(“/turtle”), Paths.get(“/turtleCopy”));
~~~
When directories are copied, the copy is shallow.
A deep copy typically requires recursion, where a method calls itself.
public void copyPath(Path source, Path target) { try { Files.copy(source, target); if(Files.isDirectory(source)) try (Stream<Path> s = Files.list(source)) { s.forEach(p -> copyPath(p, target.resolve(p.getFileName()))); } } catch(IOException e) { // Handle exception } }
The method first copies the path, whether a file or a directory. If it is a directory, only a shallow copy is performed. Next, it checks whether the path is a directory and, if it is, performs a recursive copy of each of its elements. What if the method comes across a symbolic link? Don’t worry: the JVM will not follow symbolic links when using the list() method.
Copying and Replacing Files
- By default, if the target already exists, the copy() method will throw an exception.
- You can change this behavior by providing the StandardCopyOption enum value
REPLACE_EXISTING
to the method. - The following method call will overwrite the movie.txt file if it already exists:
Files.copy(Paths.get("book.txt"), Paths.get("movie.txt"), StandardCopyOption.REPLACE_EXISTING);
For the exam, you need to know that without the REPLACE_EXISTING
option, this method will throw an exception if the file already exists.
Copying Files with I/O Streams
public static long copy(InputStream in, Path target, CopyOption… options) throws IOException public static long copy(Path source, OutputStream out) throws IOException
The Files class includes two copy() methods that operate with I/O streams.
public static long copy(InputStream in, Path target, CopyOption… options) throws IOException public static long copy(Path source, OutputStream out) throws IOException
The first method reads the contents of an I/O stream and writes the output to a file. The second method reads the contents of a file and writes the output to an I/O stream. These methods are quite convenient if you need to quickly read/write data from/to disk.