设置Java VM line.separator

时间:2010-09-14 12:48:35

标签: java properties linefeed

是否有人找到了如何在VM启动时指定Java line.separator属性的方法?我在考虑这样的事情:

java -Dline.separator="\n"

但是这并没有将“\ n”解释为换行符。有什么想法吗?

3 个答案:

答案 0 :(得分:15)

尝试使用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 Quoting部分。

答案 1 :(得分:4)

为了弥合aioobe和Bozho的答案之间的差距,我还建议不要在JVM启动时设置line.separator参数,因为这可能会破坏JVM和库代码对环境做出的许多基本假设例如,如果您依赖的库依赖于line.separator以便以跨平台方式存储配置文件,那么您只是打破了这种行为。是的,它是一个边缘案例,但这使得它变得更加邪恶,从现在开始,问题突然出现,现在你的所有代码都依赖于这个调整,而你的库是(正确)假设它不是。

也就是说,有时候这些事情是你无法控制的,就像图书馆依赖line.separator并且无法明确地覆盖这种行为一样。在这种情况下,您可能会克服价值,或者像手动重新实施或修补代码一样更痛苦。

对于那些有限的案例,我们可以覆盖line.separator,但我们必须遵守两条规则:

  1. 最小化覆盖范围
  2. 无论什么
  3. ,还原覆盖

    AutoCloseabletry-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);
      }
    }
    

    我的用例是Files.write(),这是一种非常方便的方法,除了明确依赖line.separator。通过将调用包装到Files.write(),我可以干净地指定我想要使用的行分隔符,而不用冒险将其暴露给我的应用程序的任何其他部分(请注意,这仍然不是线程安全的)。

    try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
      Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
    }
    

答案 2 :(得分:3)

如果我是你,我不会这样做。行分隔符是特定于平台的,应保持不变。如果您想编写仅限Windows或仅使用Linux的文件,请在某处定义UNIX_LINE_SEPARATOR常量并改为使用它。