有没有人找到如何line.separator
在 VM 启动时指定 Java 属性的方法?我在想这样的事情:
java -Dline.separator="\n"
但这不会将“\n”解释为换行符。有任何想法吗?
有没有人找到如何line.separator
在 VM 启动时指定 Java 属性的方法?我在想这样的事情:
java -Dline.separator="\n"
但这不会将“\n”解释为换行符。有任何想法吗?
尝试使用java -Dline.separator=$'\n'
. 这应该可以解决问题,至少在 bash 中是这样。
这是一个测试运行:
aioobe@r60:~/tmp$ cat Test.java
public class Test {
public static void main(String[] args) {
System.out.println("\"" + System.getProperty("line.separator") + "\"");
}
}
aioobe@r60:~/tmp$ javac Test.java && java -Dline.separator=$'\n' Test
"
"
aioobe@r60:~/tmp$
笔记:
该表达式$''
使用 Bash 功能ANSI-C Quoting。它扩展反斜杠转义字符,从而$'\n'
产生一个换行符(ASCII 代码 10),用单引号括起来。请参阅 Bash 手册,第3.1.2.4 节 ANSI-C 引用。
为了弥合 aioobe 和 Bozho 的答案之间的差距,我还建议不要line.separator
在 JVM 启动时设置参数,因为这可能会破坏 JVM 和库代码对正在运行的环境所做的许多基本假设。例如,如果您依赖的库on 依赖于line.separator
以跨平台方式存储配置文件,您刚刚破坏了该行为。是的,这是一个边缘案例,但是当几年后确实出现问题时,这使得它变得更加邪恶,现在你所有的代码都依赖于这个调整,而你的库(正确地)假设它不是。
也就是说,有时这些事情是您无法控制的,例如当一个库依赖line.separator
并且无法让您明确地覆盖该行为时。在这种情况下,你会被困在重写值,或者更痛苦的事情,比如手动重新实现或修补代码。
对于那些有限的情况,覆盖是可以接受的line.separator
,但我们必须遵循两条规则:
try-with-resourcesAutoCloseable
语法很好地满足了这两个要求,因此我实现了一个干净地提供两者的类。PropertiesModifier
/**
* Class which enables temporary modifications to the System properties,
* via an AutoCloseable. Wrap the behavior that needs your modification
* in a try-with-resources block in order to have your properties
* apply only to code within that block. Generally, alternatives
* such as explicitly passing in the value you need, rather than pulling
* it from System.getProperties(), should be preferred to using this class.
*/
public class PropertiesModifier implements AutoCloseable {
private final String original;
public PropertiesModifier(String key, String value) {
this(ImmutableMap.of(key, value));
}
public PropertiesModifier(Map<String, String> map) {
StringWriter sw = new StringWriter();
try {
System.getProperties().store(sw, "");
} catch (IOException e) {
throw new AssertionError("Impossible with StringWriter", e);
}
original = sw.toString();
for(Map.Entry<String, String> e : map.entrySet()) {
System.setProperty(e.getKey(), e.getValue());
}
}
@Override
public void close() {
Properties set = new Properties();
try {
set.load(new StringReader(original));
} catch (IOException e) {
throw new AssertionError("Impossible with StringWriter", e);
}
System.setProperties(set);
}
}
我的用例是 with Files.write()
,这是一种非常方便的方法,除了它明确依赖于line.separator
. 通过包装对我的调用,Files.write()
我可以清楚地指定我想要使用的行分隔符,而不会冒险将其暴露给我的应用程序的任何其他部分(当然请注意,这仍然不是线程安全的)。
try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
}
如果我是你,我不会那样做。行分隔符是特定于平台的,应该保持不变。如果您想编写仅限 Windows 或仅限 linux 的文件,请在UNIX_LINE_SEPARATOR
某处定义一个常量并改用它。