读取Java属性文件而不转义值
我的应用程序需要使用.properties文件进行配置。 在属性文件中,允许用户指定路径 问题 属性文件需要转义值,例如读取Java属性文件而不转义值,java,properties,configuration-files,Java,Properties,Configuration Files,我的应用程序需要使用.properties文件进行配置。 在属性文件中,允许用户指定路径 问题 属性文件需要转义值,例如 dir = c:\\mydir 需要 我需要某种方法来接受未转义值的属性文件,以便用户可以指定: dir = c:\mydir 两种选择: 改用这种格式 为修改后的.properties格式编写自己的解析器,不带转义 您可以尝试使用guava's:split on'='并根据生成的Iterable构建地图 此解决方案的缺点是不支持注释。您可以在加载属性之前对文件进行“预
dir = c:\\mydir
需要
我需要某种方法来接受未转义值的属性文件,以便用户可以指定:
dir = c:\mydir
两种选择:
- 改用这种格式
- 为修改后的.properties格式编写自己的解析器,不带转义
'='
并根据生成的Iterable
构建地图
此解决方案的缺点是不支持注释。您可以在加载属性之前对文件进行“预处理”,例如:
public InputStream preprocessPropertiesFile(String myFile) throws IOException{
Scanner in = new Scanner(new FileReader(myFile));
ByteArrayOutputStream out = new ByteArrayOutputStream();
while(in.hasNext())
out.write(in.nextLine().replace("\\","\\\\").getBytes());
return new ByteArrayInputStream(out.toByteArray());
}
你的代码可以这样看
Properties properties = new Properties();
properties.load(preprocessPropertiesFile("path/myfile.properties"));
这样做,您的.properties文件看起来就像您需要的一样,但您将准备好使用这些属性值
*我知道应该有更好的方法来操作文件,但我希望这能有所帮助。@pdeva:还有一个解决方案
//Reads entire file in a String
//available in java1.5
Scanner scan = new Scanner(new File("C:/workspace/Test/src/myfile.properties"));
scan.useDelimiter("\\Z");
String content = scan.next();
//Use apache StringEscapeUtils.escapeJava() method to escape java characters
ByteArrayInputStream bi=new ByteArrayInputStream(StringEscapeUtils.escapeJava(content).getBytes());
//load properties file
Properties properties = new Properties();
properties.load(bi);
正确的方法是为用户提供属性文件编辑器(或他们最喜欢的文本编辑器的插件),允许他们以纯文本形式输入文本,并以属性文件格式保存文件 如果您不希望这样做,那么您实际上是在为与属性文件相同的内容模型(或其子集)定义新格式 整个过程中,实际指定您的格式,然后考虑一种方法
- 将格式转换为规范格式,然后使用此格式加载文件,或
- 解析此格式并从中填充
对象Properties
那么,让我们看看如何定义它。普通属性文件的内容模型很简单:
- 字符串键到字符串值的映射,两者都允许任意Java字符串
- 字符串键(不包含任何空格、
或:
)到字符串值(不包含任何前导或尾随空格或换行符)的映射=
dir=c:\mydir
,键是dir
,值是c:\mydir
如果我们希望我们的键和值包含任何Unicode字符(除了上面提到的禁止字符),我们应该使用UTF-8(或UTF-16)作为存储编码,因为我们无法将字符转义到存储编码之外。否则,US-ASCII或ISO-8859-1(作为普通属性文件)或Java支持的任何其他编码就足够了,但请确保将其包含在内容模型的规范中(并确保以这种方式阅读)
由于我们限制了我们的内容模型,因此所有“危险”字符都被排除在外,我们现在可以简单地将文件格式定义为:
<simplepropertyfile> ::= (<line> <line break> )*
<line> ::= <comment> | <empty> | <key-value>
<comment> ::= <space>* "#" < any text excluding line breaks >
<key-value> ::= <space>* <key> <space>* "=" <space>* <value> <space>*
<empty> ::= <space>*
<key> ::= < any text excluding ':', '=' and whitespace >
<value> ::= < any text starting and ending not with whitespace,
not including line breaks >
<space> ::= < any whitespace, but not a line break >
<line break> ::= < one of "\n", "\r", and "\r\n" >
然后我们将这个读取器传递给我们的Properties对象(或者将内容保存到一个新文件)
相反,我们可以自己简单地解析这种格式
public Properties parse(Reader in) {
BufferedReader r = new BufferedReader(in);
Properties prop = new Properties();
Pattern keyValPattern = Pattern.compile("\s*=\s*");
String line;
while((line = r.readLine()) != null) {
line = line.trim(); // remove leading and trailing space
if(line.equals("") || line.startsWith("#")) {
continue; // ignore empty and comment lines
}
String[] kv = line.split(keyValPattern, 2);
// the pattern also grabs space around the separator.
if(kv.length < 2) {
// no key-value separator. TODO: Throw exception or simply ignore this line?
continue;
}
prop.setProperty(kv[0], kv[1]);
}
r.close();
return prop;
}
公共属性解析(读取器在中){
BufferedReader r=新的BufferedReader(in);
Properties prop=新属性();
Pattern-keyValPattern=Pattern.compile(“\s*=\s*”);
弦线;
而((line=r.readLine())!=null){
line=line.trim();//删除前导和尾随空格
if(line.equals(“”)| line.startsWith(“”){
continue;//忽略空行和注释行
}
串[]kv=线路分裂(键模式,2);
//该模式还可以抓住分隔符周围的空间。
如果(千伏长度<2){
//没有键值分隔符。TODO:引发异常还是忽略此行?
继续;
}
属性设置属性(千伏[0],千伏[1]);
}
r、 close();
返回道具;
}
同样,使用
Properties.store()
之后,我们可以将其导出为原始格式。为什么不简单地扩展Properties类以包含双正斜杠的剥离呢。它的一个很好的特性是,在程序的其余部分,您仍然可以使用原始的属性
类
public class PropertiesEx extends Properties {
public void load(FileInputStream fis) throws IOException {
Scanner in = new Scanner(fis);
ByteArrayOutputStream out = new ByteArrayOutputStream();
while(in.hasNext()) {
out.write(in.nextLine().replace("\\","\\\\").getBytes());
out.write("\n".getBytes());
}
InputStream is = new ByteArrayInputStream(out.toByteArray());
super.load(is);
}
}
使用新类很简单,如下所示:
PropertiesEx p = new PropertiesEx();
p.load(new FileInputStream("C:\\temp\\demo.properties"));
p.list(System.out);
剥离代码也可以改进,但总的原则是存在的。这不是对您的问题的确切回答,而是一个可能适合您需要的不同解决方案。在Java中,您可以使用
/
作为路径分隔符,它可以在Windows、Linux和OSX上使用。这对于相对路径特别有用
在您的示例中,您可以使用:
dir = c:/mydir
基于@Ian Harrigan,这里有一个完整的解决方案,可以从ascii文本文件中获取Netbeans属性文件(和其他转义属性文件):
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
/**
* This class allows to handle Netbeans properties file.
* It is based on the work of : http://stackoverflow.com/questions/6233532/reading-java-properties-file-without-escaping-values.
* It overrides both load methods in order to load a netbeans property file, taking into account the \ that
* were escaped by java properties original load methods.
* @author stephane
*/
public class NetbeansProperties extends Properties {
@Override
public synchronized void load(Reader reader) throws IOException {
BufferedReader bfr = new BufferedReader( reader );
ByteArrayOutputStream out = new ByteArrayOutputStream();
String readLine = null;
while( (readLine = bfr.readLine()) != null ) {
out.write(readLine.replace("\\","\\\\").getBytes());
out.write("\n".getBytes());
}//while
InputStream is = new ByteArrayInputStream(out.toByteArray());
super.load(is);
}//met
@Override
public void load(InputStream is) throws IOException {
load( new InputStreamReader( is ) );
}//met
@Override
public void store(Writer writer, String comments) throws IOException {
PrintWriter out = new PrintWriter( writer );
if( comments != null ) {
out.print( '#' );
out.println( comments );
}//if
List<String> listOrderedKey = new ArrayList<String>();
listOrderedKey.addAll( this.stringPropertyNames() );
Collections.sort(listOrderedKey );
for( String key : listOrderedKey ) {
String newValue = this.getProperty(key);
out.println( key+"="+newValue );
}//for
}//met
@Override
public void store(OutputStream out, String comments) throws IOException {
store( new OutputStreamWriter(out), comments );
}//met
}//class
导入java.io.BufferedReader;
导入java.io.ByteArrayInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
导入java.io.OutputStream;
导入java.io.OutputStreamWriter;
导入java.io.PrintWriter;
导入java.io.Reader;
导入java.io.Writer;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.List;
导入java.util.Properties;
/**
*此类允许处理Netbeans属性文件。
*它基于以下方面的工作:http://stackoverflow.com/questions/6233532/reading-java-properties-file-without-escaping-values.
*为了加载netbeans属性文件,它会覆盖这两种加载方法,同时考虑\n
*由java属性原始加载方法转义。
*@autho
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
/**
* This class allows to handle Netbeans properties file.
* It is based on the work of : http://stackoverflow.com/questions/6233532/reading-java-properties-file-without-escaping-values.
* It overrides both load methods in order to load a netbeans property file, taking into account the \ that
* were escaped by java properties original load methods.
* @author stephane
*/
public class NetbeansProperties extends Properties {
@Override
public synchronized void load(Reader reader) throws IOException {
BufferedReader bfr = new BufferedReader( reader );
ByteArrayOutputStream out = new ByteArrayOutputStream();
String readLine = null;
while( (readLine = bfr.readLine()) != null ) {
out.write(readLine.replace("\\","\\\\").getBytes());
out.write("\n".getBytes());
}//while
InputStream is = new ByteArrayInputStream(out.toByteArray());
super.load(is);
}//met
@Override
public void load(InputStream is) throws IOException {
load( new InputStreamReader( is ) );
}//met
@Override
public void store(Writer writer, String comments) throws IOException {
PrintWriter out = new PrintWriter( writer );
if( comments != null ) {
out.print( '#' );
out.println( comments );
}//if
List<String> listOrderedKey = new ArrayList<String>();
listOrderedKey.addAll( this.stringPropertyNames() );
Collections.sort(listOrderedKey );
for( String key : listOrderedKey ) {
String newValue = this.getProperty(key);
out.println( key+"="+newValue );
}//for
}//met
@Override
public void store(OutputStream out, String comments) throws IOException {
store( new OutputStreamWriter(out), comments );
}//met
}//class