Java programs are more versatile when they can be configured using command-line arguments, as you have demonstrated in several applications created in preceding hours. The java.util
package includes a class, Properties
, that enables configuration settings to be loaded from another source: a text file.
The file can be read like other file sources in Java:
• Create a File
object that represents the file.
• Create a FileInputStream
object from that File object.
• Call load()
to retrieve the properties from that input stream.
A properties file has a set of property names followed by an equal sign (=
) and their values. Here’s an example:
username=lepton
lastCommand=open database
windowSize=32
Each property has its own line, so this sets up properties named username
, lastCommand
, and windowSize
with the values “lepton”, “open database”, and “32”, respectively. (The same format was used by the ConfigWriter
class.)
The following code loads a properties file called config.dat
:
File configFile = new File("config.dat");
FileInputStream inStream = new FileInputStream(configFile);
Properties config = new Properties();
config.load(inStream);
Configuration settings, which are called properties, are stored as strings in the Properties
object. Each property is identified by a key that’s like an applet parameter. The getProperty()
method retrieves a property using its key, as in this statement:
String username = config.getProperty("username");
Because properties are stored as strings, you must convert them in some manner to use a numerical value, as in this code:
String windowProp = config.getProperty("windowSize");
int windowSize = 24;
try {
windowSize = Integer.parseInt(windowProp);
} catch (NumberFormatException exception) {
// do nothing
}
Properties can be stored by calling the setProperty()
method with two arguments—the key and value:
config.setProperty("username", "max");
You can display all properties by calling the list(
PrintStream)
method of the Properties
object. PrintStream
is the class of the out
variable of the System
class, which you’ve been using throughout the book to display output in System.out.println()
statements. The following code calls list()
to display all properties:
config.list(System.out);
After you have made changes to the properties, you can store them back to the file:
• Create a File
object that represents the file.
• Create a FileOutputStream
object from that File object.
• Call store(
OutputStream,
String)
to save the properties to the designated output stream with a description of the properties file as the string.
For the next project, you build on the ConfigWriter
application, which wrote several program settings to a file. The Configurator
application reads those settings into a Java properties file, adds a new property named runtime
with the current date and time, and saves the altered file.
Create a new empty Java file to hold the Configurator
class and enter the text from Listing 20.4.
1: import java.io.*;
2: import java.util.*;
3:
4: class Configurator {
5:
6: Configurator() {
7: try {
8: // load the properties file
9: File configFile = new File("program.properties");
10: FileInputStream inStream = new FileInputStream(configFile);
11: Properties config = new Properties();
12: config.load(inStream);
13: // create a new property
14: Date current = new Date();
15: config.setProperty("runtime", current.toString());
16: // save the properties file
17: FileOutputStream outStream = new FileOutputStream(configFile);
18: config.store(outStream, "Properties settings");
19: inStream.close();
20: config.list(System.out);
21: } catch (IOException ioe) {
22: System.out.println("IO error " + ioe.getMessage());
23: }
24: }
25:
26: public static void main(String[] arguments) {
27: Configurator con = new Configurator();
28: }
29: }
The output of the Configurator
application is shown in Figure 20.3.
The program.properties
file now contains the following text:
#Properties settings
#Tue May 12 22:51:26 EDT 2009
runtime=Tue May 12 22:51:26 EDT 2009
score=12550
level=5
username=max
The backslash character’s () formatting, which differs from the output of the application, ensures the properties file is stored properly.
During this hour, you worked with input streams and output streams that wrote bytes, the simplest way to represent data over a stream.
There are many more classes in the java.io
package to work with streams in other ways. There’s also a package of classes called java.net
that enables you to read and write streams over an Internet connection.
Byte streams can be adapted to many uses because you can easily convert bytes into other data types, such as integers, characters, and strings.
The first project of this hour, the ID3Reader
application, read bytes from a stream and converted them into a string because it was easier to read the ID3 data in this format from a song such as “Come On and Gettit” by Marian Black off the album Eccentric Soul.
Have I mentioned yet that you should buy the song?
Q. Why do some of the byte stream methods in this hour use integers as arguments? Should they be using byte
arguments?
A. There’s a difference between the bytes in a stream and the bytes represented by the byte
class. A byte
in Java has a value ranging from –128 to 127, while a byte in a stream has a value from 0 to 255. You often have to use int
when working with bytes for this reason—it can hold the values 128 to 255, whereas byte
cannot.
Q. What is Mumblety-Peg?
A. It’s a schoolyard game played by children with pocketknives.
In the simplest form, players stand and throw knives at their own feet. The one whose knife lands closest wins. Other versions involve throwing the knife at each other so the opponent has to stretch a foot to where it lands. The player who stretches too far and falls down loses.
The name comes from a rule that the winner could pound a peg into the ground with three blows of the knife. The loser had to “mumble the peg,” removing it solely with his teeth.
The game faded from popularity in the early 20th century when the world reached the collective realization that children throwing knives at each other might not be the greatest idea in the world.
To see whether you took a big enough byte from the tree of knowledge during this hour, answer the following questions about streams in Java.
1. Which of the following techniques can be used to convert an array of bytes into a string?
A. Call the array’s toString()
method.
B. Convert each byte to a character and then assign each one to an element in a String
array.
C. Call the String()
constructor method with the array as an argument.
2. What kind of stream is used to read from a file in a Java program?
A. An input stream
B. An output stream
C. Either
3. What method of the File
class can be used to determine the size of a file?
A. getSize()
B. read()
C. length()
1. C. You can deal with each byte individually, as suggested in answer B, but you can easily create strings from other data types.
2. A. An input stream is created from a File
object or by providing a filename to the input stream’s constructor method.
3. C. This method returns a long
, representing the number of bytes in the stream.
To experience the refreshing feeling of wading through another stream, test the waters with the following activities:
• Write an application that reads the ID3 tags of all MP3 files in a folder and renames the files using the artist, song, and album information (when it is provided).
• Write a program that reads a Java source file and writes it back without any changes under a new name.
• Buy a copy of the song “Come on and Gettit” by Marian Black.
To see Java programs that implement these activities, visit the book’s website at www.java24hours.com.
3.129.70.113