设置 Java VM line.separator
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3708991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Setting Java VM line.separator
提问by aioobe
Has anybody found a way how to specify the Java line.separator
property on VM startup? I was thinking of something like this:
有没有人找到如何line.separator
在 VM 启动时指定 Java属性的方法?我在想这样的事情:
java -Dline.separator="\n"
But this doesn't interprete the "\n" as linefeed character. Any ideas?
但这不会将“\n”解释为换行符。有任何想法吗?
回答by aioobe
Try using java -Dline.separator=$'\n'
. That should do the trick, at least in bash.
尝试使用java -Dline.separator=$'\n'
. 这应该可以解决问题,至少在 bash 中。
Here is a test-run:
这是一个测试运行:
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$
Note:
笔记:
The expression $''
uses the Bash feature ANSI-C Quoting. It expands backslash-escaped characters, thus $'\n'
produces a line feed (ASCII code 10) character, enclosed in single quotes. See Bash manual, section 3.1.2.4 ANSI-C Quoting.
该表达式$''
使用 Bash 功能ANSI-C Quoting。它扩展反斜杠转义字符,从而$'\n'
生成换行(ASCII 代码 10)字符,用单引号括起来。请参阅 Bash 手册,第3.1.2.4节ANSI-C 引用。
回答by dimo414
To bridge the gap between aioobe and Bozho's answers, I also would advise against setting the line.separator
parameter at JVM startup, as this potentially breaks many fundamental assumptions the JVM and library code makes about the environment being run in. For instance, if a library you depend on relies on line.separator
in order to store a config file in a cross-platform way, you've just broken that behavior. Yes, it's an edge case, but that makes it all the more nefarious when, years from now, a problem does crop up, and now all your code is dependent on this tweak being in place, while your libraries are (correctly) assuming it isn't.
为了弥合 aioobe 和 Bozho 的答案之间的差距,我还建议不要line.separator
在 JVM 启动时设置参数,因为这可能会破坏 JVM 和库代码对运行环境做出的许多基本假设。例如,如果您依赖某个库on 依赖line.separator
于以跨平台方式存储配置文件,您刚刚破坏了这种行为。是的,这是一个边缘情况,但这使得它变得更加邪恶,几年后问题确实出现了,现在你所有的代码都依赖于这个调整到位,而你的库(正确)假设它不是。
That said, sometimes these things are out of your control, like when a library relies on line.separator
and provides no way for you to override that behavior explicitly. In such a case, you're stuck overriding the value, or something more painful like re-implementing or patching the code manually.
也就是说,有时这些事情是您无法控制的,例如当一个库依赖于line.separator
并且无法让您显式覆盖该行为时。在这种情况下,您无法覆盖该值,或者更痛苦的事情,例如手动重新实现或修补代码。
For those limited cases, the it's acceptable to override line.separator
, but we've got to follow two rules:
对于那些有限的情况,覆盖是可以接受的line.separator
,但我们必须遵循两个规则:
- Minimize the scope of the override
- Revert the override no matter what
- 最小化覆盖范围
- 无论如何都要恢复覆盖
Both of these requirements are well served by AutoCloseable
and the try-with-resourcessyntax, so I've implemented a PropertiesModifier
class that cleanly provides both.
AutoCloseable
和try-with-resources语法很好地满足了这两个要求,所以我实现了一个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);
}
}
My use case was with Files.write()
, which is a very convenient method, except it explicitly relies on line.separator
. By wrapping the call to Files.write()
I can cleanly specify the line separator I want to use, without risking exposing this to any other parts of my application (take note of course, that this still isn't thread-safe).
我的用例是 with Files.write()
,这是一种非常方便的方法,除了它明确依赖于line.separator
. 通过包装对Files.write()
我的调用,我可以清楚地指定我想要使用的行分隔符,而不会有将它暴露给我的应用程序的任何其他部分的风险(当然请注意,这仍然不是线程安全的)。
try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
}
回答by Bozho
I wouldn't do that if I were you. The line-separator is platform specific, and should remain so. If you want to write windows-only or linux-only files, define a UNIX_LINE_SEPARATOR
constant somewhere and use it instead.
如果我是你,我就不会那样做。行分隔符是特定于平台的,并且应该保持如此。如果您想编写仅适用于 Windows 或仅适用于 linux 的文件,请在UNIX_LINE_SEPARATOR
某处定义一个常量并改用它。