我正在用Java替代传统应用程序。要求之一是必须将旧应用程序使用的ini文件原样读取到新的Java应用程序中。此ini文件的格式是常见的Windows样式,带有标题部分和键=值对,使用#作为注释字符。
我尝试使用Java中的Properties类,但是如果不同的标头之间存在名称冲突,那当然是行不通的。
因此,问题是,读取此INI文件和访问密钥的最简单方法是什么?
我正在用Java替代传统应用程序。要求之一是必须将旧应用程序使用的ini文件原样读取到新的Java应用程序中。此ini文件的格式是常见的Windows样式,带有标题部分和键=值对,使用#作为注释字符。
我尝试使用Java中的Properties类,但是如果不同的标头之间存在名称冲突,那当然是行不通的。
因此,问题是,读取此INI文件和访问密钥的最简单方法是什么?
Answers:
我使用的库是ini4j。它轻巧,可以轻松解析ini文件。此外,它不使用对10,000个其他jar文件的神秘依赖,因为设计目标之一是仅使用标准Java API
这是有关如何使用库的示例:
Ini ini = new Ini(new File(filename));
java.util.prefs.Preferences prefs = new IniPreferences(ini);
System.out.println("grumpy/homePage: " + prefs.node("grumpy").get("homePage", null));
IniFile
上课了,请尝试Ini ini = new Ini(new File("/path/to/file"));
Wini
该类,如“一分钟”教程中所说明;在prefs.node("something").get("val", null)
没有工作我预期的方式。
正如提到的,ini4j可以用来实现这一目标。我再举一个例子。
如果我们有这样的INI文件:
[header]
key = value
以下应显示value
到STDOUT:
Ini ini = new Ini(new File("/path/to/file"));
System.out.println(ini.get("header", "key"));
查看教程以获取更多示例。
只需80行:
package windows.prefs;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class IniFile {
private Pattern _section = Pattern.compile( "\\s*\\[([^]]*)\\]\\s*" );
private Pattern _keyValue = Pattern.compile( "\\s*([^=]*)=(.*)" );
private Map< String,
Map< String,
String >> _entries = new HashMap<>();
public IniFile( String path ) throws IOException {
load( path );
}
public void load( String path ) throws IOException {
try( BufferedReader br = new BufferedReader( new FileReader( path ))) {
String line;
String section = null;
while(( line = br.readLine()) != null ) {
Matcher m = _section.matcher( line );
if( m.matches()) {
section = m.group( 1 ).trim();
}
else if( section != null ) {
m = _keyValue.matcher( line );
if( m.matches()) {
String key = m.group( 1 ).trim();
String value = m.group( 2 ).trim();
Map< String, String > kv = _entries.get( section );
if( kv == null ) {
_entries.put( section, kv = new HashMap<>());
}
kv.put( key, value );
}
}
}
}
}
public String getString( String section, String key, String defaultvalue ) {
Map< String, String > kv = _entries.get( section );
if( kv == null ) {
return defaultvalue;
}
return kv.get( key );
}
public int getInt( String section, String key, int defaultvalue ) {
Map< String, String > kv = _entries.get( section );
if( kv == null ) {
return defaultvalue;
}
return Integer.parseInt( kv.get( key ));
}
public float getFloat( String section, String key, float defaultvalue ) {
Map< String, String > kv = _entries.get( section );
if( kv == null ) {
return defaultvalue;
}
return Float.parseFloat( kv.get( key ));
}
public double getDouble( String section, String key, double defaultvalue ) {
Map< String, String > kv = _entries.get( section );
if( kv == null ) {
return defaultvalue;
}
return Double.parseDouble( kv.get( key ));
}
}
这是一个使用apache类HierarchicalINIConfiguration的简单但功能强大的示例:
HierarchicalINIConfiguration iniConfObj = new HierarchicalINIConfiguration(iniFile);
// Get Section names in ini file
Set setOfSections = iniConfObj.getSections();
Iterator sectionNames = setOfSections.iterator();
while(sectionNames.hasNext()){
String sectionName = sectionNames.next().toString();
SubnodeConfiguration sObj = iniObj.getSection(sectionName);
Iterator it1 = sObj.getKeys();
while (it1.hasNext()) {
// Get element
Object key = it1.next();
System.out.print("Key " + key.toString() + " Value " +
sObj.getString(key.toString()) + "\n");
}
Commons Configuration具有许多运行时依赖项。至少需要commons-lang和commons-logging。根据您所使用的功能,可能需要其他库(有关详细信息,请参见前面的链接)。
或者使用标准Java API,您可以使用java.util.Properties:
Properties props = new Properties();
try (FileInputStream in = new FileInputStream(path)) {
props.load(in);
}
Properties
该类无法正确获取包含\的值
在18行中,将java.util.Properties
解析扩展为多个部分:
public static Map<String, Properties> parseINI(Reader reader) throws IOException {
Map<String, Properties> result = new HashMap();
new Properties() {
private Properties section;
@Override
public Object put(Object key, Object value) {
String header = (((String) key) + " " + value).trim();
if (header.startsWith("[") && header.endsWith("]"))
return result.put(header.substring(1, header.length() - 1),
section = new Properties());
else
return section.put(key, value);
}
}.load(reader);
return result;
}
另一个选择是Apache Commons Config还具有一个用于从INI文件加载的类。它确实具有一些运行时依赖性,但是对于INI文件,它仅需要Commons集合,lang和日志记录。
我在项目上使用了Commons Config及其属性和XML配置。它非常易于使用,并支持一些非常强大的功能。
您可以尝试JINIFile。是Delphi中TIniFile的翻译,但适用于Java
我个人更喜欢孔夫子。
很好,因为它不需要任何外部依赖关系,它很小-仅16K,并在初始化时自动加载您的ini文件。例如
Configurable config = Configuration.getInstance();
String host = config.getStringValue("host");
int port = config.getIntValue("port");
new Connection(host, port);
at4的解决方案非常优雅和简单。它适用于所有合理的 ini文件。但是,我见过很多有在非转义空格键。
为了解决这个问题,我下载并修改了的副本java.util.Properties
。尽管这有点不合常规,而且是短期的,但实际的mod只是几行而已,非常简单。我将向JDK社区提出一个建议,以包括这些更改。
通过添加内部类变量:
private boolean _spaceCharOn = false;
我控制与扫描键/值分离点有关的处理。我用一个小的私有方法替换了空格字符搜索代码,该方法根据上述变量的状态返回一个布尔值。
private boolean isSpaceSeparator(char c) {
if (_spaceCharOn) {
return (c == ' ' || c == '\t' || c == '\f');
} else {
return (c == '\t' || c == '\f');
}
}
此方法在private方法内的两个地方使用load0(...)
。
还有一种公共方法可以将其打开,但是Properties
如果空间分隔符对您的应用程序来说不是问题,则最好使用原始版本的。
如果有兴趣,我愿意将代码发布到我的 IniFile.java
文件中。适用于的任何版本Properties
。
使用@Aerospace的答案,我意识到INI文件包含没有任何键值的段是合法的。在这种情况下,应该在找到任何键值之前(例如,Java 8的最小更新)对顶级映射进行添加:
Path location = ...;
try (BufferedReader br = new BufferedReader(new FileReader(location.toFile()))) {
String line;
String section = null;
while ((line = br.readLine()) != null) {
Matcher m = this.section.matcher(line);
if (m.matches()) {
section = m.group(1).trim();
entries.computeIfAbsent(section, k -> new HashMap<>());
} else if (section != null) {
m = keyValue.matcher(line);
if (m.matches()) {
String key = m.group(1).trim();
String value = m.group(2).trim();
entries.get(section).put(key, value);
}
}
}
} catch (IOException ex) {
System.err.println("Failed to read and parse INI file '" + location + "', " + ex.getMessage());
ex.printStackTrace(System.err);
}
就这么简单.....
//import java.io.FileInputStream;
//import java.io.FileInputStream;
Properties prop = new Properties();
//c:\\myapp\\config.ini is the location of the ini file
//ini file should look like host=localhost
prop.load(new FileInputStream("c:\\myapp\\config.ini"));
String host = prop.getProperty("host");