Transcript ch16_nn
Chapter 16 – Files, Buffers, and Channels
Using Files for Input and Output
A Simple Text-File Example – HTML File Generator
A Website Reader
Object I/O
Output with: ObjectOutputStream,
FileOutputStream
Input with: ObjectInputStream, FileInputStream
Character Sets and File-Access Options
Buffered Text File I/O
Primitive Buffers with Random Access
Channel I/O and Memory-Mapped Files
The File Class
Walking a Directory Tree With a “glob” Pattern Matcher
1
Using Files for Input and Output
So far, most input has come from the keyboard and
most output has been to the console window.
Keyboard and console input/output (I/O) is
temporary, not permanent.
For permanent I/O, use files with extensions that
suggests how the data is formatted and the type of
program that understands that format.
Benefit of reading input from a file:
Allows input to be reused without having to re-enter the
input via the keyboard.
Benefits of saving output to a file:
Allows output to be re-viewed without having to rerun the
program.
Allows program chaining where the output of one program
is used as the input for another program.
2
HTML File Generator
Example input file, historyChannel.txt:
When Chihuahuas Ruled the World
Around 8000 B.C., the great Chihuahua Dynasty ruled the world.
What happened to this ancient civilization?
Join us for an extraordinary journey into the history
of these noble beasts.
Resulting output file, historyChannel.html:
<!doctype html>
<html>
<head>
<title>When Chihuahuas Ruled the World</title>
</head>
<body>
<h1>When Chihuahuas Ruled the World</h1>
<p>
Around 8000 B.C., the great Chihuahua Dynasty ruled the world.
What happened to this ancient civilization?
<p>
Join us for an extraordinary journey into the history
of these noble beasts.
</body>
</html>
3
HTML File Generator
import java.util.Scanner;
import java.io.PrintWriter;
import java.nio.file.Paths;
public class HTMLGenerator
{
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
String filenameIn;
// original file's name
int dotIndex;
// position of dot in filename
String filenameOut;
// HTML file's name
String line;
// a line from the input file
System.out.print("Enter file's name: ");
filenameIn = stdIn.nextLine();
// Compose the new filename
dotIndex = filenameIn.lastIndexOf(".");
if (dotIndex == -1)
// no dot found
filenameOut = filenameIn + ".html";
else
// dot found
filenameOut =
filenameIn.substring(0, dotIndex) + ".html";
4
HTML File Generator
try (
Scanner fileIn = new Scanner(Paths.get(filenameIn));
PrintWriter fileOut = new PrintWriter(filenameOut))
{
// First line used for title and header elements
line = fileIn.nextLine();
if (line == null)
{
System.out.println(filenameIn + " is empty.");
}
else
{
// Write the top of the HTML page.
fileOut.println("<!doctype html>");
fileOut.println("<html>");
fileOut.println("<head>");
fileOut.println("<title>" + line + "</title>");
fileOut.println("</head>");
fileOut.println("<body>");
fileOut.println("<h1>" + line + "</h1>");
5
HTML File Generator
while (fileIn.hasNextLine())
{
line = fileIn.nextLine();
// Blank lines generate p tags.
if (line.isEmpty())
fileOut.println("<p>");
else
fileOut.println(line);
} // end while
// Write ending HTML code.
fileOut.println("</body>");
fileOut.println("</html>");
} // end else
} // end try and close fileOut and fileIn automatically
catch (Exception e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
} // end catch
} // end main
} // end class HTMLGenerator
6
A Website Reader
7
Reading text from a remote website is like reading text from a file
– in both cases, the text comes in as a stream of bytes.
import java.util.Scanner;
import java.net.*;
// URL, URLConnection
import java.io.InputStream;
public class WebPageReader
{
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
Scanner webIn;
URL url;
URLConnection connection;
InputStream inStream;
// stream of bytes
int i = 0, maxI;
// line number and max line number
A website reader needs a try block because the URL constructor
can throw a MalformedURLException, the openConnection
method call can throw an IOException, and the
getInputStream method call can throw an IOException.
A Website Reader
try
{
System.out.print("Enter a full URL address: ");
url = new URL(stdIn.nextLine());
connection = url.openConnection();
inStream = connection.getInputStream();
webIn = new Scanner(inStream);
System.out.print("Enter number of lines: ");
maxI = stdIn.nextInt();
while (i < maxI && webIn.hasNext())
{
System.out.println(webIn.nextLine());
i++;
}
inStream.close();
} // end try
catch (Exception e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
} // end main
} // end WebPageReader
8
Object File I/O
9
Problem:
In OOP, most data is in object format, and the structure of objects
is user-specified. So there is no universal format for storing objects
in files, and each object’s variables must be stored separately using
a format that is appropriate for that type of object. This makes
writing or reading an object’s data to or from a file very tedious.
Solution:
Automate this process with Java’s “serialization” service.
To get this service, append the following to the heading of any
class you want to use this service:
implements Serializable
The JVM handles all the details.
10
Object File I/O
Output:
ObjectOutputStream fileOut;
try
{
fileOut = new ObjectOutputStream(
new FileOutputStream(filename));
fileOut.writeObject(testObject);
fileOut.close();
}
open file
Input:
ObjectInputStream fileIn;
try
{
fileIn = new ObjectInputStream(
open file
new FileInputStream(filename));
testObject = (TestObject) fileIn.readObject();
fileIn.close();
}
Adding an Updated Version of a
Previously Written Object
11
If you ask ObjectOutputStream's writeObject method
to output a modified version of the same object again while
the file is still open, the serializing software recognizes the
repetition and outputs just a reference to the previously
output object.
To make Java append the latest state of an object instead of
just a reference to the originally output object, invoke
ObjectOutputStream's reset method before you output
an updated version of a previously output object:
fileOut.writeObject(testObject);
testObject.set(<some-attribute>);
fileOut.reset();
fileOut.writeObject(testObject);
File Access Options
12
Up until now, the types of file-access options we have employed have
been the default options built into the particular file-handling
constructors we used.
But sometimes you need another option. You can display the names of
all of Java’s standard open options by executing this code:
for (StandardOpenOption opt : StandardOpenOption.values())
{
System.out.println(opt);
}
Here are some Examples:
APPEND, CREATE, READ, TRUNCATE_EXISTING, WRITE.
For example, to open an existing file to add some more objects to it,
you might use this:
ObjectOutputStream fileOut = new ObjectOutputStream(
Files.newOutputStream(path, StandardOpenOption.APPEND)));
Character Sets
13
All text representation employs a certain set of characters. You can
determine the name of the default character set used on your
computer by importing java.nio.charset.Charset and calling
Charset.defaultCharset().
You can determine the names of all the particular character sets
your own computer can identify, read, and write by executing this
code fragment:
for (String s : Charset.availableCharsets().keySet())
{
System.out.println(s);
}
To modify the previous chapter’s ReadFromFile program to read
data that was written in the particular character set having the
name, “US-ASCII”, instead of using the one-parameter Scanner
constructor, use this two-parameter Scanner constructor:
fileIn = new Scanner(Paths.get(filename), "US-ASCII");
Buffered Text File I/O
For large and/or remote file I/O, you should always employ an
intermediate buffer. A buffer is a sequential storage structure that
acts like a first-in first-out (FIFO) queue, or “waiting line.”
Since a buffer resides in high-speed memory, during program
execution the program can transfer data into or out of the buffer
much more quickly than into or out of a file in persistent storage.
The following BufferedWriteToFile program shows how to write text
to a file through a buffer. The Files class’s class method,
public static BufferedWriter newBufferedWriter(Path path,
Charset cs, OpenOption... options) throws IOException
returns a BufferedWriter object, configured for a particular
character set and particular open options.
The OpenOption... notation is a varargs, which means we may
supply any number of arguments of the specified type, including
none.
14
BufferedWriteToFile Program
15
This program writes a string through a buffer to a text file. The
user specifies whether it is the only string in the file or is appended
to previous string(s) in the file.
import
import
import
import
java.util.Scanner;
java.io.BufferedWriter;
java.nio.file.*;
// Paths, Files, StandardOpenOption
java.nio.charset.Charset;
public class BufferedWriteToFile
{
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
String fileName, openOption;
System.out.print("Enter filename: ");
fileName = stdIn.nextLine();
System.out.print("Enter TRUNCATE_EXISTING or APPEND: ");
openOption = stdIn.nextLine();
BufferedWriteToFile Program
try (BufferedWriter fileOut = Files.newBufferedWriter(
Paths.get(fileName),
Charset.defaultCharset(),
StandardOpenOption.CREATE,
StandardOpenOption.valueOf(openOption)))
{
System.out.println("Enter a line of text:");
fileOut.write(stdIn.nextLine() + "\n");
} // end try
catch (Exception e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
} // end main
} // end BufferedWriteToFile class
16
BufferedWriteToFile Program
This shows how to write two lines of text into a file.
Sample session 1:
Enter filename: Ecclesiastes
Enter TRUNCATE_EXISTING or APPEND: TRUNCATE_EXISTING
Enter a line of text:
Do not be over-virtuous
Sample session 2:
Enter filename: Ecclesiastes
Enter TRUNCATE_EXISTING or APPEND: APPEND
Enter a line of text:
nor play too much the sage;
17
BufferedReadFromFile Program
18
The following program shows how to read text from a file through
a buffer. File’s newBufferedReader method also includes
specification of the character set. It does not accept any openoption specification – it just assumes we want the READ option
only. The imports and local variables are the same as those in the
BufferedWriteToFile program.
Assuming the file created by the inputs in the previous slide, this is
what the user gets by running the BufferedReadFromFile program
with input equal to the name of the file created in the
BufferedWriteToFile program:
Sample session:
Enter filename: Ecclesiastes
Do not be over-virtuous
nor play too much the sage;
BufferedReadFromFile Program
import
import
import
import
java.util.Scanner;
java.io.BufferedReader;
java.nio.file.*;
// Paths, Files
java.nio.charset.Charset;
public class BufferedReadFromFile
{
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
String fileName;
System.out.print("Enter filename: ");
fileName = stdIn.nextLine();
19
BufferedReadFromFile Program
try (BufferedReader fileIn = Files.newBufferedReader(
Paths.get(fileName),
Charset.defaultCharset()))
{
while (fileIn.ready())
{
System.out.println(fileIn.readLine());
}
} // end try
catch (Exception e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
} // end main
} // end BufferedReadFromFile class
20
Web Reading With Buffer
You can also use Java’s BufferedReader to read from the Web. To do
this, create a URL object. Then create a URLConnection. Then create an
InputStream. Then use that InputStream to create the
InputStreamReader. Then use that InputStreamReader to create a
BufferedReader. Here is the sequence of operations:
URL url = new URL(webAddress);
URLConnection connection = url.openConnection();
InputStream in = connection.getInputStream();
BufferedReader reader =
new BufferedReader(new InputStreamReader(in));
21
The URL and URLConnection are in the java.net package. The
InputStream, InputStreamReader, and BufferedReader classes
are in the java.io package.If you need a character set different from
your computer’s default character set, you can specify the character set
with a second argument supplied to an alternate InputStreamReader
constructor.
Primitive Buffers With Random Access
22
We can also buffer primitive data, like byte, char, short, int,
float, long, and double.
To facilitate this, the java.nio package provides the abstract
class, Buffer, and its abstract descendants: ByteBuffer,
CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer,
LongBuffer, and ShortBuffer.
Use <buffer-class>.allocate(<elements>) to create a new
buffer and establish its capacity (maximum number of elements).
Since computer systems universally transmit and store data as
bytes, the ByteBuffer class plays a central role. It provides
single-variable put and get methods that make conversions
between other primitive types and the byte type.
With help from these methods, the data in the array underlying a
ByteBuffer can represent any primitive type, any combination of
primitive types, or any combination of primitive types and Object
types.
Buffer Methods for Random Access
Buffer methods storing element information:
23
int capacity() returns the total number of elements.
int limit() returns the total number of accessible elements.
int position() returns the index of the next element.
boolean hasRemaining() says there are more accessible elements.
int remaining() returns the accessible elements after position.
Buffer methods manipulating element information:
Buffer clear() clears the buffer.
Buffer limit(int newLimit) sets number of accessible elements.
Buffer mark() sets the mark at the current position.
Buffer position(int newPosition) sets element position index.
Buffer rewind() changes the current position to zero.
Buffer reset() changes the current position to the mark.
Buffer flip() sets the limit to the current position and then sets the
position to zero.
Elementary ByteBuffer Methods
24
There are get and put methods for each type of primitive variable:
byte, char, short, int, long, float, double.
Zero-parameter get methods like getChar() are relative. They
return the primitive at the calling buffer’s current position and then
increment that position to the next element.
One-parameter get methods like getChar(int index) are
absolute. The index parameter specifies the primitive’s position.
Absolute get methods do not change the buffer’s current position.
One-parameter put methods like putChar(char value) are
relative. They write the primitive at the calling buffer’s current
position and then they increment that position to the next element.
Two-parameter put methods like putChar(int index, char
value) are absolute. The index parameter specifies the destination
position, but these absolute put methods do not change the buffer’s
current position.
ByteBuffer Methods
25
The method,
public ByteBuffer put(ByteBuffer source)
copies all remaining source bytes to the calling buffer, starting at
the calling buffer’s current position. Since the two buffers’ limit and
position values may be different, you can use this method to copy
an arbitrary subset of the data in the first buffer to an arbitrary
position in the second buffer.
The next slide contains a simple program that uses ByteBuffer’s
relative putInt method to put a single int value at the beginning
of a ByteBuffer. Then it uses ByteBuffer’s absolute
putDouble method to put a single double value into that same
ByteBuffer, with seven blank spaces between the end of the
four-byte int and the start of the eight-byte double.
ByteBufferAccess Program
import java.nio.ByteBuffer;
public class ByteBufferAccess
{
public static void main(String[] args)
{
int bufLength = 4 + 7 + 8; // int + empty spaces + double
ByteBuffer buffer1 = ByteBuffer.allocate(bufLength);
ByteBuffer buffer2 = ByteBuffer.allocate(bufLength);
// populate output buffer
buffer1.putInt(2);
System.out.println("afterIntPos= " + buffer1.position());
buffer1.putDouble(11, 2.0);
System.out.println("afterDblPos= " + buffer1.position());
// Transfer everything to input buffer
buffer1.rewind();
buffer2.put(buffer1);
// display transferred data
buffer2.flip();
System.out.println(buffer2.getInt());
System.out.println(buffer2.getDouble(11));
} // end main
} // end ByteBufferAccess class
26
ByteBuffer Array Methods
27
The class method,
public static ByteBuffer wrap(byte[] byteArray)
creates, populates, and returns a ByteBuffer filled with the parameter’s elements.
The relative one-parameter method,
put(byte[] source),
copies all bytes in the source array into the calling buffer, starting at the calling
buffer’s current position.
The absolute three-parameter method,
put(byte[] source, int offset, int length)
copies length bytes from the source array, starting at offset array index, into the
calling buffer, starting at its current position.
The method,
byte[] array()
returns a view of the array that underlies the calling buffer.
The additional view methods, asCharBuffer, asShortBuffer, asIntBuffer,
asLongBuffer, asFloatBuffer, and asDoubleBuffer, expose a ByteBuffer’s
underlying array as other primitive types.
Other Buffer Array Methods
28
Other classes in the java.nio package − CharBuffer, ShortBuffer,
IntBuffer, LongBuffer, FloatBuff, and DoubleBuffer – define
methods like these:
get(char[] destination)
get(char[] destination, int offset, int length),
put(char[] source)
put(char[] source, int offset, int length)
With these methods, it’s relatively easy to copy an array of primitives that
are not bytes to or from a ByteBuffer, using statements like these:
buffer.asDoubleBuffer().put(doubles)
buffer.asDoubleBuffer().get(doubles)
A powerful feature of the combination of a ByteBuffer and the
DoubleBuffer obtained from ByteBuffer’s asDoubleBuffer method
is the independence of the two buffers’ position variables.
ByteBufferArrayAccess Program
import java.util.Arrays;
import java.nio.ByteBuffer;
public class ByteBufferArrayAccess
{
public static void main(String[] args)
{
int[] ints = new int[]{1, 1, 2, 3, 5, 8};
String str =
"The purpose of computing is insight, not numbers.";
double[] doubles = new double[]{1.0, 2.0, 1.5, 1.67, 1.6};
byte[] strBytes = str.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(
4 * ints.length + strBytes.length + 8 * doubles.length);
// put to buffer
buffer.asIntBuffer().put(ints);
buffer.position(4 * ints.length);
buffer.put(strBytes).asDoubleBuffer().put(doubles);
29
ByteBufferArrayAccess Program
// fill working arrays with zeros and rewind buffer
Arrays.fill(ints, 0);
Arrays.fill(strBytes, (byte) 0);
Arrays.fill(doubles, 0.0);
str = "";
buffer.rewind();
// get from buffer
buffer.asIntBuffer().get(ints);
buffer.position(4 * ints.length);
buffer.get(strBytes).asDoubleBuffer().get(doubles);
str = new String(strBytes);
// display transferred data
System.out.println(Arrays.toString(ints));
System.out.println(str);
System.out.println(Arrays.toString(doubles));
} // end main
} // end ByteBufferArrayAccess class
Sample session:
[1, 1, 2, 3, 5, 8]
The purpose of computing is insight, not numbers.
[1.0, 2.0, 1.5, 1.67, 1.6]
30
Character Sets Revisited
31
In the ByteBufferArrayAccess program, the getBytes method call
that converts the specified String to a byte array in the declarations and
the later String constructor with the byte[] argument both use the
default character set. For a different character set, use the getBytes
method and the String constructor that accept character-set specification.
Specifically, include this additional import:
import java.nio.charset.Charset;
To convert the specified String to a byte array, replace the strBytes
declaration with something like this:
byte[] strBytes = str.getBytes(Charset.forName("US-ASCII"));
To convert the byte array back into a String, use something like this:
str = new String(strBytes, Charset.forName("US-ASCII"));
The choice of “US-ASCII” here is arbitrary. In practice, you might use one
of the other character sets.
Channel I/O
32
A channel is a large-scale view of what’s in a file. To put
heterogeneous data into a file, first put primitives into buffers, and
then put those buffers into channels. Conversely, to get
heterogeneous data from a file, first extract the buffers from the
channels, and then extract the primitives from the buffers.
Channel position and size are measured in bytes. If you don’t
explicitly alter the channel’s position, as you write bytes, position
automatically increments and size automatically expands as
required.
If you specify a starting place, you could go back and over-write any
sequence of bytes. Then you could use channel’s size method to
restore its position to just after the last contained byte and continue
on from there.
After writing from any combination of buffers, you can read with a
different combination of buffers.
Channel I/O
To work with file channels, include these imports:
import java.nio.channels.FileChannel;
import java.nio.file.*;
To specify the file you want, create a new Path, using something
like this:
System.out.print("Enter filename: ");
Path path = Paths.get(stdIn.nextLine());
To open the file for either reading or writing (over any pre-existing
data), in a try-with-resources header, create a channel like this:
try(FileChannel channel = FileChannel.open(
path, StandardOpenOption.CREATE,
StandardOpenOption.WRITE, StandardOpenOption.READ))
{
// ...
} // end try
Because the file opens in a try-with resources header, it closes
automatically at the end of the try block.
33
General FileChannel Methods
static FileChannel open(
Path path, OpenOption... options)
long position()
Returns this channel’s current position in the file.
FileChannel position(long newPosition)
Sets this channel’s current position in the file.
public long size()
Returns the current size of this channel’s file.
MappedByteBuffer map(
FileChannel.MapMode mode, long position, long size)
Creates a persistent view of size bytes of this channel’s file, starting
at this channel’s position, with modes READ_ONLY, READ_WRITE
(mutable view), or PRIVATE (copy).
34
FileChannel Write Methods
35
int write(ByteBuffer source)
Starting at this channel ‘s position or at the end if opened for
APPEND, writes the remaining bytes from the source buffer.
long write(ByteBuffer[] sources)
Starting at this channel ‘s position or at the end if opened for
APPEND, writes the remaining bytes from the sources buffers.
long write(
ByteBuffer[] sources, int offset, int length)
Starting at this channel’s position or at the end if opened for
APPEND, writes the remaining bytes from length buffers starting at
offset in the sources array.
int write(ByteBuffer source, long start)
Starting at start in this channel, writes the remaining bytes in the
source buffer.
FileChannel Read Methods
36
int read(ByteBuffer destination)
Reads the remaining bytes from this channel into the remaining
positions in the destination buffer.
long read(ByteBuffer[] destinations)
Reads the remaining bytes from this channel into the remaining
positions in the buffers in the destinations array.
long read(
ByteBuffer[] destinations, int offset, int length)
Reads the remaining bytes from this channel into the remaining
positions in length buffers, starting at offset in the
destinations array.
int read(ByteBuffer destination, long start)
Reads bytes after start in this channel into the remaining positions
in destination buffer. Does not change this channel’s position.
ChanneledFileAccess Program
import
import
import
import
import
java.nio.channels.FileChannel;
java.io.IOException;
java.util.*;
// Arrays, Scanner
java.nio.*;
// ByteBuffer, MappedByteBuffer
java.nio.file.*; // Path, Paths, StandardOpenOption
public class ChanneledFileAccess
{
public final static int TEXT = 12;
public final static int RECORD = 4 + TEXT + 8;
// This adds one buffered record to a file channel.
public void writeRecord(FileChannel channel,
int id, String string, double value) throws IOException
{
byte[] strBytes =
Arrays.copyOfRange(string.getBytes(), 0, TEXT);
ByteBuffer buffer = ByteBuffer.allocate(RECORD);
buffer.putInt(id).put(strBytes).putDouble(value);
buffer.rewind();
channel.write(buffer);
} // end writeRecord
37
ChanneledFileAccess Program
public void readRecord(FileChannel channel,
int recordIndex) throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(RECORD);
channel.read(buffer, recordIndex * RECORD);
buffer.rewind();
displayRecord(buffer);
} // end readRecord
private static void displayRecord(ByteBuffer buffer)
{
int id;
byte[] strBytes = new byte[TEXT];
double value;
id = buffer.getInt();
buffer.get(strBytes);
value = buffer.getDouble();
System.out.printf("%4d %10s %6.1f\n",
id, new String(strBytes), value);
} // end displayRecord
38
ChanneledFileAccess Program
public static void main(String[] args)
{
Scanner stdIn = new Scanner(System.in);
ChanneledFileAccess cio = new ChanneledFileAccess();
ByteBuffer mappedBuffer = ByteBuffer.allocate(3 * RECORD);
System.out.print("Enter filename: ");
Path path = Paths.get(stdIn.nextLine());
try(FileChannel channel = FileChannel.open(
path, StandardOpenOption.CREATE,
StandardOpenOption.WRITE, StandardOpenOption.READ))
{
cio.writeRecord(channel, 1, "first", 1.0);
cio.writeRecord(channel, 2, "second", 2.0);
cio.writeRecord(channel, 3, "third", 3.0);
System.out.print("Enter file's record index (0,1,2): ");
cio.readRecord(channel, stdIn.nextInt());
mappedBuffer = channel.map(
FileChannel.MapMode.READ_WRITE, 0, channel.size());
}
39
ChanneledFileAccess Program
catch(IOException e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
// Now, channel is gone, but mappedBuffer still exists.
System.out.print("Enter map's record index (0,1,2): ");
mappedBuffer.position(stdIn.nextInt() * RECORD);
displayRecord(mappedBuffer);
} // end main
} // end class ChanneledFileAccess
Sample
Enter
Enter
3
Enter
2
session:
filename: Records
file's record index (0,1,2): 2
third
3.0
map's record index (0,1,2): 1
second
2.0
40
Defining and Manipulating Paths
41
The best way to specify a file is to describe the path leading to it using the
Files.get() method, like this:
Path path = Files.get("<path-to-directory-or-file>");
An absolute path starts at the directory-tree’s root (a leading forward slash).
The relative path to the current directory is a single dot. The relative path to
a file in the current directory is the name of that file. If the current directory
contains a sisterSonia subdirectory, the relative path to a nieceNedra
file in that subdirectory is sisterSonia/nieceNedra.
The relative path to the directory above the current directory is a pair of
dots (..). If the parent directory contains another directory called
auntAgnes, the relative path to a cousinCora file in that other directory
is ../auntAgnes/cousinCora.
The absolute path, pathA, corresponding to the relative path, pathR, is:
Path pathA = pathR.toAbsolutePath();
The relative path from absolute path pathA1 to absolute path pathA2 is:
Path path1_to_path2 = pathA1.relativize(pathA2);
The combination of path1 followed by path2 is:
Path pathComb = path1.resolve(path2);
Creating, Moving, Copying, and Deleting Files
42
The method call, Files.exists(path) returns true if the file identified
by path already exists and you have permission to access that file.
To create a new directory, use Path.createDirectory(pathToDir).
Use Files.isDirectory(path) to see if path leads to a directory. Use
Files.isRegularFile to see if path leads to a regular file.
To move or copy an existing directory or file from path1 to path2, in a try
block use:
Files.move(path1, path2, <option(s)>);
Files.copy(path1, path2, <option(s)>);
If there is no existing file at path2, omit the option(s) argument.
To replace an existing path2 file, include the option:
StandardCopyOption.REPLACE_EXISTING
To delete the file, path, in a try block use Files.delete(path);
Before you can delete a directory, you must first delete or remove all the
files it contains.
DirectoryDescription Program
import java.nio.file.*; // Path, Paths, DirectoryStream, Files
public class DirectoryDescription
{
public static void main(String[] args)
{
Path pathToDirectory = Paths.get(".");
try (DirectoryStream<Path> paths =
Files.newDirectoryStream(pathToDirectory))
{
for (Path path : paths)
{
System.out.printf("%-30s%6d bytes\n",
path.getFileName(), Files.size(path));
}
}
43
DirectoryDescription Program
catch (Exception e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
} // end main
} // end DirectoryDescription class
Sample session:
DirectoryDescription.class
DirectoryDescription.java
FileSizesGUI.class
FileSizesGUI.java
1793
772
1813
1975
bytes
bytes
bytes
bytes
44
Walking a Directory Tree − FindFiles Program
45
Instead of listing all files in a particular directory, let’s locate filenames
containing a specified substring anywhere in or below a specified directory.
A substring specification called a “glob” can contain any number of singlecharacter wildcards, ?, and the substring wildcards, *.
import java.nio.file.*;
import java.util.Scanner;
import java.io.IOException;
// Path, Paths, Files
public class FindFiles
{
public static void main(String[] args)
{
Path startDir;
Scanner stdIn = new Scanner(System.in);
String pattern; // ? is wild char; * is wild substring
FileVisitor visitor;
Walking a Directory Tree With “glob” Pattern Matcher
System.out.println(
"Enter absolute path to starting directory:");
startDir = Paths.get(stdIn.nextLine());
System.out.print("Enter filename search pattern: ");
pattern = stdIn.nextLine();
visitor = new FileVisitor("glob:" + pattern);
try
{
Files.walkFileTree(startDir, visitor);
}
catch (IOException e)
{
System.out.println(e.getClass());
System.out.println(e.getMessage());
}
} // end main
} // end FindFiles class
46
Walking a Directory Tree – FileVisitor Class
// for
//
import
import
import
SimpleFileVisitor, Path, PathMatcher, FileSystem,
FileSystems, FileVisitResult, and Files:
java.nio.file.*;
java.nio.file.attribute.BasicFileAttributes;
java.io.IOException;
public class FileVisitor extends SimpleFileVisitor<Path>
{
private PathMatcher matcher;
private int tab = 0;
// depth in tree
//*****************************************************
public FileVisitor(String syntaxAndPattern)
{
FileSystem system = FileSystems.getDefault();
this.matcher = system.getPathMatcher(syntaxAndPattern);
} // end constructor
47
Walking a Directory Tree – FileVisitor Class
public FileVisitResult preVisitDirectory(Path path,
BasicFileAttributes attributes) throws IOException
{
for (int i=0; i<tab; i++)
{
System.out.print("
");
}
System.out.println(path.getFileName()); // directory
tab++;
return FileVisitResult.CONTINUE;
} // end preVisitDirectory
//*****************************************************
public FileVisitResult postVisitDirectory(Path path,
IOException exc)
{
tab--;
return FileVisitResult.CONTINUE;
} // end postVisitDirectory
48
Walking a Directory Tree – FileVisitor Class
public FileVisitResult visitFile(Path path,
BasicFileAttributes attributes) throws IOException
{
Path name = path.getFileName();
if (name !=null && matcher.matches(name))
{
for (int i=0; i<tab; i++)
{
System.out.print("
");
}
System.out.printf("%-25s%6d bytes\n",
name, Files.size(path));
// ordinary file
}
return FileVisitResult.CONTINUE;
} // end visitFile
} // end FileVisitor class
49
Walking a Directory Tree − Output
Sample session:
Enter absolute path to starting directory:
/Users/raydean/Documents/John/ITPJSourceCode/pgmsInChapBodies
Enter filename search pattern: *2.java
pgmsInChapBodies
chap01
chap03
chap04
chap05
chap06
Mouse2.java
1264 bytes
MouseDriver2.java
687 bytes
chap07
Car2.java
950 bytes
Employee2.java
448 bytes
chap08
chap09
chap10
SpeedDialList2.java
1459 bytes
chap11
50
Walking a Directory Tree − Output
chap12
Dealership2.java
DealershipDriver2.java
Manager2.java
SalesPerson2.java
chap13
Car2.java
Employee2.java
Hourly2.java
Pets2.java
Salaried2.java
chap14
GetIntFromUser2.java
PrintLineFromFile2.java
StudentList2.java
chap15
WriteObject2.java
WriteTextFile2.java
chap16
FactorialButton2.java
chap17
1240
817
297
413
bytes
bytes
bytes
bytes
984
588
832
713
621
bytes
bytes
bytes
bytes
bytes
978 bytes
1210 bytes
1056 bytes
999 bytes
804 bytes
2980 bytes
51
Walking a Directory Tree − Alternatives
Suppose all you want to see is the directory structure, not any of the
files in that structure. For this result, run the program with nothing but
a simple carriage return (Enter) for the pattern specification.
Suppose what you want to see is a listing of matching files only, with
each file identified as the total path from the directory’s root to that
file. For this result, do not override the preVisitDirectory and
postVisitDirectory methods. That is, delete or comment out
these two methods in the FileVisitor class. Also dlete the tab
variable and replace the for loop in the visitFile method with this
statement:
name = name.toAbsolutePath();
Suppose you want to truncate or terminate the search. In the
FileVisitor class, with appropriate code adjustments, use of these:
return FileVisitResult.SKIP_SIBLINGS
return FileVisitResult.SKIP_SUBTREE
return FileVisitResult.TERMINATE
52