History of Java

hedgebornabaloneΛογισμικό & κατασκευή λογ/κού

2 Δεκ 2013 (πριν από 3 χρόνια και 8 μήνες)

85 εμφανίσεις

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


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
.


7

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


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.





9

Object File I/O


Output:


ObjectOutputStream fileOut;


try


{


fileOut = new ObjectOutputStream(


new FileOutputStream(filename));


fileOut.writeObject(testObject);


fileOut.close();


}


Input:


ObjectInputStream fileIn;


try


{


fileIn = new ObjectInputStream(


new FileInputStream(filename));


testObject = (TestObject) fileIn.readObject();


fileIn.close();


}

open file

open file

10

Adding an Updated Version of a
Previously Written Object


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);

11

File Access Options


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)));

12

Character Sets


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");



13

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


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 java.util.Scanner;

import java.io.BufferedWriter;

import java.nio.file.*; // Paths, Files, StandardOpenOption

import 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();

15

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


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 open
-
option 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;



18

BufferedReadFromFile Program

import java.util.Scanner;

import java.io.BufferedReader;

import java.nio.file.*; // Paths, Files

import 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));



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.

21

Primitive Buffers With Random Access


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.

22

Buffer

Methods for Random Access


Buffer

methods storing element information:


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.


23

Elementary
ByteBuffer

Methods


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.

24

ByteBuffer

Methods


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
.



25

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


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.

27

Other Buffer Array Methods


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.



28

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


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.


31

Channel I/O




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.

32

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 R
EAD_ONLY
,
READ_WRITE



(mutable view), or
PRIVATE

(copy).



34

FileChannel

Write Methods


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.



35

FileChannel

Read Methods


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 l
ength

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
.


36

ChanneledFileAccess Program

import java.nio.channels.FileChannel;

import java.io.IOException;

import java.util.*; // Arrays, Scanner

import java.nio.*; // ByteBuffer, MappedByteBuffer

import 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 session
:

Enter filename:
Records

Enter file's record index (0,1,2):
2


3 third 3.0

Enter map's record index (0,1,2):
1


2 second 2.0


40

Defining and Manipulating Paths


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);






41

Creating, Moving, Copying, and Deleting Files


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.








42

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 1793 bytes

DirectoryDescription.java 772 bytes

FileSizesGUI.class 1813 bytes

FileSizesGUI.java 1975 bytes


44

Walking a Directory Tree −
FindFiles

Program


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 single
-
character wildcards,
?
,
and the substring wildcards,
*
.

import java.nio.file.*; // Path, Paths, Files

import java.util.Scanner;

import java.io.IOException;



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;







45

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 SimpleFileVisitor, Path, PathMatcher, FileSystem,

// FileSystems, FileVisitResult, and Files:

import java.nio.file.*;

import java.nio.file.attribute.BasicFileAttributes;

import 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 1240 bytes


DealershipDriver2.java 817 bytes


Manager2.java 297 bytes


SalesPerson2.java 413 bytes


chap13


Car2.java 984 bytes


Employee2.java 588 bytes


Hourly2.java 832 bytes


Pets2.java 713 bytes


Salaried2.java 621 bytes


chap14


GetIntFromUser2.java 978 bytes


PrintLineFromFile2.java 1210 bytes


StudentList2.java 1056 bytes


chap15


WriteObject2.java 999 bytes


WriteTextFile2.java 804 bytes


chap16


FactorialButton2.java 2980 bytes


chap17

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