Appearance
Properties File
When writing applications, it is often necessary to read and write configuration files. For example, user settings:
# Last opened file:
last_open_file=/data/hello.txt
# Auto-save interval in seconds:
auto_save_interval=60
The characteristic of configuration files is that their key-value pairs are generally of type String-String, so we can represent them using Map<String, String>
.
Since configuration files are very common, the Java Collections Framework provides a Properties
class to represent a set of "configurations." Due to historical reasons, Properties
is essentially a Hashtable
, but we only need to use the Properties
interface for reading and writing configurations.
Reading Configuration Files
Reading a configuration file with Properties
is very simple. The default extension for configuration files in Java is .properties
, with each line represented as key=value
and lines starting with #
being comments. Here is a typical configuration file:
# setting.properties
last_open_file=/data/hello.txt
auto_save_interval=60
This .properties
file can be read from the file system as follows:
java
String f = "setting.properties";
Properties props = new Properties();
props.load(new java.io.FileInputStream(f));
String filepath = props.getProperty("last_open_file");
String interval = props.getProperty("auto_save_interval", "120");
As we can see, there are three steps to read a configuration file using Properties
:
- Create a
Properties
instance. - Call
load()
to read the file. - Call
getProperty()
to retrieve the configuration.
When calling getProperty()
, if the key does not exist, it will return null
. We can also provide a default value, which will be returned when the key does not exist.
You can also read .properties
files from the classpath, as the load(InputStream)
method accepts an InputStream
, which can be a byte stream that is not necessarily a file stream, but could also be a resource stream read from a JAR file:
java
Properties props = new Properties();
props.load(getClass().getResourceAsStream("/common/setting.properties"));
Let's try reading a byte stream from memory:
java
// properties
import java.io.*;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws IOException {
String settings = "# test" + "\n" + "course=Java" + "\n" + "last_open_date=2019-08-07T12:35:01";
ByteArrayInputStream input = new ByteArrayInputStream(settings.getBytes("UTF-8"));
Properties props = new Properties();
props.load(input);
System.out.println("course: " + props.getProperty("course"));
System.out.println("last_open_date: " + props.getProperty("last_open_date"));
System.out.println("last_open_file: " + props.getProperty("last_open_file"));
System.out.println("auto_save: " + props.getProperty("auto_save", "60"));
}
}
If there are multiple .properties
files, you can repeatedly call load()
to read them, with later loaded key-value pairs overwriting earlier ones:
java
Properties props = new Properties();
props.load(getClass().getResourceAsStream("/common/setting.properties"));
props.load(new FileInputStream("C:\\conf\\setting.properties"));
The code above demonstrates a common use case of Properties
: you can place a default configuration file in the classpath and then create another configuration file based on the machine environment to override some of the default configurations.
The design of Properties
is intended to store String type key-value pairs. However, Properties
is derived from Hashtable
, which has design issues. To maintain compatibility, it cannot be modified now. In addition to getProperty()
and setProperty()
methods, there are also get()
and put()
methods inherited from Hashtable
, which take Object
as parameters. When using Properties
, avoid calling these methods inherited from Hashtable
.
Writing Configuration Files
If you modify a Properties
instance using setProperty()
, you can write the configuration back to a file so that the latest configuration is available the next time the application starts. Use the store()
method to write to a configuration file:
java
Properties props = new Properties();
props.setProperty("url", "http://www.liaoxuefeng.com");
props.setProperty("language", "Java");
props.store(new FileOutputStream("C:\\conf\\setting.properties"), "This is a properties comment");
Encoding
Early versions of Java specified that .properties
files must be encoded in ASCII (ISO8859-1). If Chinese characters are involved, they must be represented as name=\u4e2d\u6587
, which is very awkward. Since JDK 9, .properties
files can now use UTF-8 encoding.
However, it is important to note that since load(InputStream)
always reads byte streams using ASCII encoding by default, this can lead to garbled text. We need to use another overloaded method load(Reader)
for reading:
java
Properties props = new Properties();
props.load(new FileReader("settings.properties", StandardCharsets.UTF_8));
This will allow you to read Chinese characters correctly. The difference between InputStream
and Reader
is that one is a byte stream and the other is a character stream. The character stream represents data as char
in memory, which avoids encoding issues.
Summary
The Properties
class provided by the Java Collections Framework is used to read and write .properties
configuration files, which can use UTF-8 encoding.
You can read .properties
files from the file system, classpath, or any other location.
When reading and writing Properties
, be sure to only use getProperty()
and setProperty()
methods, and avoid calling inherited methods like get()
and put()
.