Chapter 14 I/O - Tips Flashcards
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.
NOTE
> [!NOTE]I/O
APIs do not support symbolic links
, NIO.2
includes full support for creating, detecting, and navigating symbolic links
within the file system.
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.
I/O API
s do not supportsymbolic links
NIO.2
supportsymbolic links
- both the
I/O and NIO.2
classes can interact with aURI
- 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.
Operating System File Separators
System.out.print(System.getProperty("file.separator")
);
Java offers a system property to retrieve the local separator character for the current environment:
System.out.print(System.getProperty("file.separator")
);
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.
Creating a File
or Path
-
java.io.File
- public
File
(String pathname
) - public
File
(File parent
,String child
) - public
File
(String parent
,String child
)
- public
-
java.nio.file.Path
- public static Path
of
(String first, String… more) - public static Path
of
(URI uri)
- public static Path
-
java.nio.file.Paths
- public static Path
get
(String first, String… more) - public static Path
get
(URI uri)
- public static Path
-
java.io.File class
is cread by calling itsconstructor
.-
3 constructors
public File(String pathname)
public File(File parent, String child)
public File(String parent, String child)
- 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.
-
3 constructors
-
java.nio.file.Path interface
, obtain a Path object is to use a static factory method defined on Path or Paths.
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.-
java.nio.file.Path
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.io.nio.file.Files
NIO.2 helper class,Files
operates onPath
instances
Switching between File and Path
default File toFile()
public Path toPath()
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
- public static FileSystem getDefault()
- public abstract Path getPath(String first, String… more)
- 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
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()
TABLE 14.3 Common File
and Path
operations
-
Gets name of file/directory
public String getName()
getFileName()
-
Retrieves parent directory or
null
if there is nonepublic String getParent()
getParent()
-
Checks if file/directory is absolute path
public boolean isAbsolute()
isAbsolute()
TABLE 14.4 Common File
and Files
operations
I/O
-
Deletes file/directory
public boolean delete()
-
Checks if file/directory exists
public boolean exists()
-
Retrieves absolute path of file/directory
public String getAbsolutePath()
-
Checks if resource is directory
public boolean isDirectory()
-
Checks if resource is file
public boolean isFile()
-
Returns the time the file was last modified
public long lastModified()
-
Retrieves number of
bytes
in filepublic long length()
-
Lists contents of directory
public File[] listFiles()
-
Creates directory
public boolean mkdir()
-
Creates directory including any nonexistent parent directories
public boolean mkdirs()
-
Renames file/directory denoted
public boolean renameTo(File dest)
TABLE 14.4 Common File
and Files
operations
NIO.2
-
Deletes file/directory
public static void delete(Path path) throws IOException
public static boolean deleteIfExists(Path path) throws IOException
-
Checks if file/directory exists
public static boolean exists(Path path, LinkOption... options)
-
Retrieves absolute path of file/directory
-
Path toAbsolutePath()
<–this is Path interface method
-
-
Checks if resource is directory
public static boolean isDirectory(Path path, LinkOption... options)
-
Checks if resource is file
public static boolean isRegularFile(Path path, LinkOption... options)
-
Returns the time the file was last modified
public static FileTime getLastModifiedTime(Path path, LinkOption... options) throws IOException
-
Retrieves number of
bytes
in filepublic static long size(Path path) throws IOException
-
Lists contents of directory
public static Stream<Path> list(Path dir) throws IOException
-
Creates directory
public static Path createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException
-
Creates directory including any nonexistent parent directories
public static Path createDirectories(Path dir, FileAttribute<?>... attrs) throws IOException
-
Renames file/directory denoted
public static Path move(Path source, Path target, CopyOption... options) throws IOException
TABLE 14.4 Common File
and Files
operations
-
Deletes file/directory
public boolean delete()
deleteIfExists(Path p) throws IOException
-
Checks if file/directory exists
public boolean exists()
exists(Path p, LinkOption… o)
-
Retrieves absolute path of file/directory
public String getAbsolutePath()
-
Path toAbsolutePath()
<–this is Path interface method
-
Checks if resource is directory
public boolean isDirectory()
isDirectory(Path p, LinkOption… o)
-
Checks if resource is file
public boolean isFile()
isRegularFile(Path p, LinkOption… o)
-
Returns the time the file was last modified
public long lastModified()
getLastModifiedTime(Path p, LinkOption… o) throws IOException
-
Retrieves number of
bytes
in filepublic long length()
size(Path p) throws IOException
-
Lists contents of directory
public File[] listFiles()
list(Path p) throws IOException
-
Creates directory
public boolean mkdir()
createDirectory(Path p, FileAttribute… a) throws IOException
-
Creates directory including any nonexistent parent directories
public boolean mkdirs()
createDirectories(Path p, FileAttribute… a) throws IOException
-
Renames file/directory denoted
public boolean renameTo(File dest)
move(Path src, Path dest, CopyOption… o) throws IOException
Closing the Stream
Stream object inside a try-with-resources?
36: try (Stream stream = Files.list(path)) { 37: stream.forEach(p -> 38: System.out.println(" " + p.getName())); 39: }
- 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
- LinkOption
- StandardCopyOption
- StandardOpenOption
- FileVisitOption
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); }
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 CopyOptionAnswer
Interacting with NIO.2 Path
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)
-
Path getFileName()
Returns the name of the file or directory denoted by this path as a Path object. The file name is the farthest element from the root in the directory hierarchy.
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
Path subpath(int beginIndex, int endIndex)
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
-
Path getFileName()
Returns the name of the file or directory denoted by this path as a Path object. The file name is the farthest element from the root in the directory hierarchy. -
Path getParent()
Returns the parent path, or null if this path does not have a parent. -
Path getRoot()
Returns the root component of this path as a Path object, or null if this path does not have a root component.
- 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.
Resolving Paths
public Path resolve(String p)
public Path resolve(Path p)
- On the exam, when you see
resolve()
, thinkconcatenation
. - The
resolve()
method providesoverloaded
versions that let you pass either aPath
orString
parameter.public Path resolve(String p)
public Path resolve(Path p)
-
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.
Applyresolve()
to anabsolute path
and arelative path
:
Path path1 = Path.of("/cats/../panther"); Path path2 = Path.of("food"); System.out.println(path1.resolve(path2));
output :/cats/../panther/food
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()
.
Path path3 = Path.of("/turkey/food"); System.out.println(path3.resolve("/tiger/cage"));
output :/tiger/cage
Relativizing a Path
-
Path relativize(Path other)
Constructs a relative path between this path and a given path.
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 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));
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 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
var path1 = Path.of("fish.txt"); var path2 = Path.of("friendly/birds.txt"); System.out.println(path1.relativize(path2)); // ../friendly/birds.txt System.out.println(path2.relativize(path1)); // ../../fish.txt
Path path3 = Paths.get("E:\\habitat"); Path path4 = Paths.get("E:\\sanctuary\\raven\\poe.txt"); System.out.println(path3.relativize(path4)); // ..\sanctuary\raven\poe.txt System.out.println(path4.relativize(path3)); // ..\..\..\habitat
Normalizing a Path
-
Path normalize()
Returns a path that is this path with redundant name elements eliminated.
Thenormalize()
method removes any redundant elements, which includes any"." or "directory/.."
occurrences.
The normalize()
method removes any redundant elements, which includes any "." or "directory/.."
occurrences.
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
The normalize()
method does not remove all of the path symbols, only the ones that can be reduced.
var p3 = Path.of("../../fish.txt"); System.out.println(p3.normalize()); // ../../fish.txt
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
-
Path toRealPath(LinkOption... options)throws IOException
Returns the real path of an existing file.
- 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 Pathresolve
(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
* Making Directories
* public static Path createDirectory
(Path dir, FileAttribute<?>
… attrs) throws IOException
* public static Path createDirectories
(Path dir, FileAttribute<?>
… attrs) throws IOException
* Copying Files
* public static Path copy
(Path source, Path target, CopyOption… options) throws IOException
-
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
- public static long
-
Moving or Renaming Paths with move()
- public static Path
move
(Path source, Path target, CopyOption… options) throws IOException
- public static Path
-
Deleting a File with delete() and deleteIfExists()
- public static void
delete
(Path path) throws IOException - public static boolean
deleteIfExists
(Path path) throws IOException
- public static void
-
Making Directories
Both of these methods also accept an optional list of FileAttribute<?>
values to apply to the newly created directory or directories.-
public static Path
createDirectory
(Path dir, FileAttribute<?>
… attrs) throws IOException- create a directory
- throw an exception if it already exists or if the paths leading up to the directory do not exist
-
public static Path
createDirectories
(Path dir, FileAttribute<?>
… attrs) throws IOException- Creates the target directory along with any nonexistent parent directories leading up to the path
- Do nothing If all of the directories already exist
- Use to ensure a directory exists and create it if it does not.
-
public static Path
-
Copying Files
The Files class provides a method for copying files and directories within the file system.
When directories are copied, the copy isshallow
.
A shallow copy means that the files and subdirectories within the directory are not copied.- public static Path copy(Path source, Path target, CopyOption… options) throws IOException
-
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
- public static long copy(
-
Moving or Renaming Paths with move()
- public static Path move(Path source, Path target, CopyOption… options) throws IOException
-
Deleting a File with delete() and deleteIfExists()
- public static void delete(Path path) throws IOException
- public static boolean deleteIfExists(Path path) throws IOException
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.
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 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
Files.copy(Paths.get("book.txt"), Paths.get("movie.txt"), StandardCopyOption.REPLACE_EXISTING);
- By default, if the target already exists, the
copy()
method will throw an exception. - You can change this behavior by providing the
StandardCopyOption
enum valueREPLACE_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.
The following are examples of each copy() method:
try (var is = new FileInputStream("source-data.txt")) { // Write I/O stream data to a file Files.copy(is, Paths.get("/mammals/wolf.txt")); } Files.copy(Paths.get("/fish/clown.xsl"), System.out);
While we used FileInputStream in the first example, the I/O stream could have been any valid I/O stream including website connections, in-memory stream resources, and so forth. The second example prints the contents of a file directly to the System.out stream.
Copying Files into a Directory
For the exam, it is important that you understand how the copy()
method operates on both files and directories.
What do you think is the result of executing the following process?
var file = Paths.get("food.txt"); var directory = Paths.get("/enclosure"); Files.copy(file, directory);
- If you said it would create a new file at /enclosure/food.txt, you’re way off.
- It throws an exception.
- The command tries to create a new file named /enclosure.
- Since the path /enclosure already exists, an exception is thrown at runtime.
- On the other hand, if the directory did not exist, the process would create a new file with the contents of food.txt, but the file would be called
/enclosure
. - Remember, we said files may not need to have extensions, and in this example, it matters.
The correct way to copy the file into the directory is to do the following :
var file = Paths.get("food.txt"); var directory = Paths.get("/enclosure/food.txt"); Files.copy(file, directory);
Moving or Renaming Paths with move()
public static Path move(Path source, Path target, CopyOption… options) throws IOException
The Files class provides a useful method for moving or renaming files and directories.
public static Path move(Path source, Path target, CopyOption… options) throws IOException
The following sample code uses the move() method:
Files.move(Path.of("C:\\zoo"), Path.of("C:\\zoo-new")); Files.move(Path.of("C:\\user\\addresses.txt"), Path.of("C:\\zoo-new\\addresses2.txt"));
- The first example renames the zoo directory to a zoo-new directory, keeping all of the original contents from the source directory.
- The second example moves the addresses.txt file from the directory user to the directory zoo-new and renames it addresses2.txt.
Similarities between move()
and copy()
- Like
copy()
,move()
requiresREPLACE_EXISTING
to overwrite the target if it exists; otherwise, it will throw an exception. - Also like copy(), move() will not put a file in a directory if the source is a file and the target is a directory. Instead, it will create a new file with the name of the directory.
Performing an Atomic Move
Files.move(Path.of("mouse.txt"), Path.of("gerbil.txt"), StandardCopyOption.ATOMIC_MOVE);
Another enum value that you need to know for the exam when working with the move() method is the StandardCopyOption value ATOMIC_MOVE
.
Files.move(Path.of("mouse.txt"), Path.of("gerbil.txt"), StandardCopyOption.ATOMIC_MOVE);
- You may remember the atomic property from Chapter 13, “Concurrency,” and the principle of an atomic move is similar.
- An atomic move is one in which a file is moved within the file system as a single indivisible operation.
- Put another way, any process monitoring the file system never sees an incomplete or partially written file.
- If the file system does not support this feature, an
AtomicMoveNotSupportedException
will be thrown. - Note that while
ATOMIC_MOVE
is available as a member of the StandardCopyOption type, it will likely throw an exception if passed to a copy() method.
Deleting a File with delete() and deleteIfExists()
public static void delete(Path path) throws IOException public static boolean deleteIfExists(Path path) throws IOException
The Files class includes two methods that delete a file or empty directory within the file system.
public static void delete(Path path) throws IOException public static boolean deleteIfExists(Path path) throws IOException
- To delete a directory, it must be empty. Both of these methods throw an exception if operated on a nonempty directory.
- In addition, if the path is a symbolic link, the symbolic link will be deleted, not the path that the symbolic link points to.
-
The methods differ on how they handle a path that does not exist.
- The
delete()
method throws an exception if the path does not exist, - while the
deleteIfExists()
method returnstrue
if the delete was successful orfalse
otherwise.
- The
- Similar to createDirectories(), deleteIfExists() is useful in situations where you want to ensure that a path does not exist and delete it if it does.
Here we provide sample code that performs delete() operations:
Files.delete(Paths.get("/vulture/feathers.txt")); Files.deleteIfExists(Paths.get("/pigeon"));
- The first example deletes the feathers.txt file in the vulture directory, and it throws a NoSuchFileException if the file or directory does not exist.
- The second example deletes the pigeon directory, assuming it is empty. If the pigeon directory does not exist, the second line will not throw an exception.
Comparing Files with isSameFile()
and mismatch()
-
public static boolean isSameFile(Path path, Path path2) throws IOException
Tests if two paths locate the same file. -
public static long mismatch(Path path, Path path2) throws IOException
Finds and returns the position of the first mismatched byte in the content of two files, or -1L if there is no mismatch. The position will be in the inclusive range of 0L up to the size (in bytes) of the smaller file.
Since a path may include path symbols and symbolic links within a file system, the equals()
method can’t be relied on to know if two Path instances refer to the same file.
Luckily, there is the isSameFile() method.
- This method takes two Path objects as input,
- resolves all path symbols,
- and follows symbolic links.
- Despite the name, the method can also be used to determine whether two Path objects refer to the same directory.
- While most uses of
isSameFile()
will trigger an exception if the paths do not exist, there is a special case in which it does not. - If the two path objects are equal in terms of
equals()
, the method will just return true without checking whether the file exists.
Assume that the file system exists, as shown in Figure 14.4, with a symbolic link from /animals/snake to /animals/cobra.
Given the structure defined in Figure 14.4, what does the following output?
System.out.println(Files.isSameFile( Path.of("/animals/cobra"), Path.of("/animals/snake"))); System.out.println(Files.isSameFile( Path.of("/animals/monkey/ears.png"), Path.of("/animals/wolf/ears.png")));
Since snake is a symbolic link to cobra, the first example outputs true.
In the second example, the paths refer to different files, so false is printed.
mismatch()
Sometimes you want to compare the contents of the file rather than whether it is physically the same file. For example, we could have two files with text hello.
- The mismatch() method was introduced in Java 12 to help us out here.
- It takes two Path objects as input.
- The method returns
-1
if the files are the same; - otherwise, it returns the index of the first position in the file that differs.
System.out.println(Files.mismatch( Path.of("/animals/monkey.txt"), Path.of("/animals/wolf.txt")));
Suppose monkey.txt contains the name Harold and wolf.txt contains the name Howler. The previous code prints 1 in that case because the second position is different, and we use zero-based indexing in Java. Given those values, what do you think this code prints?
System.out.println(Files.mismatch( Path.of("/animals/wolf.txt"), Path.of("/animals/monkey.txt")));
The answer is the same as the previous example. The code prints 1 again. The mismatch() method is symmetric and returns the same result regardless of the order of the parameters.
Understanding I/O Stream Fundamentals
- The contents of a file may be accessed or written via an I/O stream,
- which is a list of data elements presented sequentially.
- Each type of I/O stream segments data into a wave or block in a particular way.
- On top of that, some I/O stream classes read or write larger groups of bytes or characters at a time, specifically those with the word Buffered in their name.
> [!NOTE]
Although the java.io API is full of I/O streams that handle characters, strings, groups of bytes, and so on, nearly all are built on top of reading or writing an individual byte or an array of bytes at a time.
Higher-level I/O streams exist for convenience as well as performance.
Although I/O streams are commonly used with file I/O, they are more generally used to handle the reading/writing of any sequential data source. For example, you might construct a Java application that submits data to a website using an output stream and reads the result via an input stream.
Higher-level I/O streams exist for convenience
as well as performance
.
Byte Streams vs. Character Streams
The java.io API defines two
sets of I/O stream classes for reading and writing I/O streams:
-
byte
I/O streams- read/write
binary data (0s and 1s)
- class names that end in
InputStream
orOutputStream
- read/write
- and
character
I/O streams.- read/write
text
data - class names that end in
Reader
orWriter
- read/write
The API frequently includes similar classes for both byte and character I/O streams
, such as FileInputStream
and FileReader
.
> [!NOTE]
Throughout the chapter, we refer to both InputStream and Reader as input streams, and we refer to both OutputStream and Writer as output streams.
The byte I/O streams are primarily used to work with binary data, such as an image or executable file, while character I/O streams are used to work with text files. For example, you can use a Writer class to output a String value to a file without necessarily having to worry about the underlying character encoding of the file.
- The byte I/O streams are primarily used to work with binary data, such as an image or executable file,
- while character I/O streams are used to work with text files.
- For example, you can use a Writer class to output a String value to a file without necessarily having to worry about the underlying character encoding of the file.
- The
character encoding
determines how characters are encoded and stored in bytes in an I/O stream and later read back or decoded as characters. - Although this may sound simple, Java supports a wide variety of character encodings, ranging from ones that may use one byte for Latin characters, UTF-8 and ASCII for example, to using two or more bytes per character, such as UTF-16.
- For the exam, you don’t need to memorize the character encodings, but you should be familiar with the names.
Character Encoding in Java
Charset usAsciiCharset = Charset.forName("US-ASCII"); Charset utf8Charset = Charset.forName("UTF-8"); Charset utf16Charset = Charset.forName("UTF-16");
In Java, the character encoding can be specified using the Charset class
by passing a name value to the static Charset.forName() method
, such as in the following examples:
Charset usAsciiCharset = Charset.forName("US-ASCII"); Charset utf8Charset = Charset.forName("UTF-8"); Charset utf16Charset = Charset.forName("UTF-16");
Java supports numerous character encodings, each specified by a different standard name value.