When noodling on my project of choice, I found that I wanted to read a configuration file lying in my main game folder. So I made this simple, probably buggy, class to handle the parsing duties for me.
It reads text streams that look like this:
config.cfg
Code:
resolution=800x600
fullscreen=true
multisampling=8
And allows them to be accessed like a Map (the class extends HashMap<String,String>). To get one of the configuration properties, you'd do something like this;
Code:
//Make a ConfigFile
ConfigFile configFile = new ConfigFile("config.cfg");
//Returns the string "800x600"
configFile.get("resolution");
//Returns the string "true"
configFile.get("fullscreen");
I've also added a couple convenience methods that will parse booleans and base-10 integers for you.
Code:
//Returns true
configFile.getBoolean("fullscreen");
//Returns 8
configFile.getInteger("multisampling");
Should you alter the entries in the map, and desire to return it to it's former pristine state, you can call reset() to return it to the state it was in just after construction, or you can call repopulate() in order to add the entries from the config file to the map again, overriding any existing values.
Without further ado, the code.
Code:
import java.io.InputStream;
import java.util.HashMap;
import java.util.Scanner;
/**
* A set of configuration properties derived from a file and accessible as a
* map.
*
* @author Cameron Seebach
*
*/
public class ConfigFile extends HashMap<String, String> {
/**
* The serialVersionUID of the ConfigFile class.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = -7456741886840905637L;
/**
* The Scanner through which the config file is read.
*/
private final Scanner scanner;
public ConfigFile(String fileName) {
this(getStreamFor(fileName));
}
/**
* Creates a ConfigFile from the given input stream.
*
* @param input
* the input stream to read for configuration information
*/
public ConfigFile(InputStream input) {
this(new Scanner(input));
}
/**
* Creates a ConfigFile from the given Scanner.
*
* @param input
* the Scanner to read for configuration information
*/
private ConfigFile(Scanner input) {
scanner = input;
repopulate();
}
private static InputStream getStreamFor(String fileName){
return Thread.currentThread().getContextClassLoader()
.getResourceAsStream(fileName);
}
/**
* Reset this ConfigFile to the way it was when you created it.
*/
public void reset(){
clear();
repopulate();
}
/**
* Puts all the configuration properties and values from the file into the
* hashmap.
*/
public void repopulate() {
scanner.reset();
while (scanner.hasNextLine()) {
String nextLine = scanner.nextLine();
if (nextLine.startsWith("//"))
continue;
String[] splitResults = nextLine.split(" = ");
if (splitResults.length != 2)
continue;
String propertyName = splitResults[0].trim();
String propertyValue = splitResults[1].trim();
put(propertyName, propertyValue);
}
}
/**
* Returns true if the given property currently exists and is associated
* with a boolean value in this ConfigProperties.
*
* @param propertyName
* the name of the property to test for
* @return true if the given property exists and is associated with a
* boolean value. otherwise, false
*/
public boolean containsBoolean(String propertyName) {
return getBoolean(propertyName) != null;
}
/**
* @param propertyName
* @return
*/
public Boolean getBoolean(String propertyName) {
String result = get(propertyName);
if (result != null)
return parseBoolean(result);
return null;
}
/**
* @param bool
* @return
*/
private Boolean parseBoolean(String bool) {
if (bool.equalsIgnoreCase("true")) {
return true;
} else if (bool.equalsIgnoreCase("false"))
return false;
return null;
}
public boolean containsInteger(String propertyName) {
return getInteger(propertyName) != null;
}
/**
* @param propertyName
* @return
*/
public Integer getInteger(String propertyName) {
String result = get(propertyName);
if (result != null)
return parseInteger(result);
return null;
}
/**
* @param result
* @return
*/
private Integer parseInteger(String result) {
try {
return Integer.valueOf(result);
} catch (NumberFormatException e) {
return null;
}
}
}
I'm afraid I have still managed to make a mess of things. But if I try to make it perfect, it will never see the light of day! Hope someone finds this useful.