设置Java VM line.separator

发布于 2024-09-19 20:18:24 字数 159 浏览 4 评论 0原文

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

java -Dline.separator="\n"

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

Has anybody found a way how to specify the Java line.separator property on VM startup? I was thinking of something like this:

java -Dline.separator="\n"

But this doesn't interprete the "\n" as linefeed character. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

荒岛晴空 2024-09-26 20:18:24

尝试使用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=

注意:

表达式 $'' 使用 Bash 功能 ANSI-C 引用。它扩展反斜杠转义字符,因此 $'\n' 生成换行符(ASCII 代码 10)字符,并用单引号括起来。请参阅 Bash 手册,部分 3.1.2.4 ANSI-C 引用< /a>.

\n' Test " " aioobe@r60:~/tmp$

注意:

表达式 $'' 使用 Bash 功能 ANSI-C 引用。它扩展反斜杠转义字符,因此 $'\n' 生成换行符(ASCII 代码 10)字符,并用单引号括起来。请参阅 Bash 手册,部分 3.1.2.4 ANSI-C 引用< /a>.

Try using java -Dline.separator=$'\n'. That should do the trick, at least in 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=

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.

\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.

夏末 2024-09-26 20:18:24

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

也就是说,有时这些事情是您无法控制的,例如当库依赖于 line.separator 且无法为您提供显式覆盖该行为的方法时。在这种情况下,您将陷入覆盖该值的困境,或者遇到更痛苦的事情,例如手动重新实现或修补代码。

对于那些有限的情况,覆盖 line.separator 是可以接受的,但我们必须遵循两个规则:

  1. 最小化覆盖范围
  2. 无论如何恢复覆盖

这两个要求都得到了很好的满足通过 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);
}

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.

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.

For those limited cases, the it's acceptable to override line.separator, but we've got to follow two rules:

  1. Minimize the scope of the override
  2. Revert the override no matter what

Both of these requirements are well served by AutoCloseable and the try-with-resources syntax, so I've implemented a PropertiesModifier class that cleanly provides both.

/**
 * 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).

try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) {
  Files.write(file, ImmutableList.of(line), Charsets.UTF_8);
}
Bonjour°[大白 2024-09-26 20:18:24

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

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.

不一样的天空 2024-09-26 20:18:24

对于 Windows 用户来说,使用 java -Dline.separator=\n 切换行分隔符并不容易,因为 Windows CMD 会破坏属性值,但您可以使用 java @argfile > 相反。

只需打开 Windows CMD.EXE 为操作系统样式行分隔符属性创建一个配置文件:

echo -Dline.separator="\n"   > gnu.linesep.args
echo -Dline.separator="\r\n" > windows.linesep.args

然后您可以使用 GNU/Linux 的行分隔符行为在 Windows 上调用您的应用程序:

java @gnu.linesep.args ... etc

您还可以使 GNU/ Linux 启动使用文件与 Windows 行分隔符进行交互:

java @windows.linesep.args ... etc
# which is same as the direct approach mentioned by aioobe:
java -Dline.separator=

请参阅此答案中的示例测试 如何强制 Windows 上的 Java 标准输出使用“\n”行分隔符?

\r\n' ... etc

请参阅此答案中的示例测试 如何强制 Windows 上的 Java 标准输出使用“\n”行分隔符?

For Windows users it isn't easy to switch line separator with java -Dline.separator=\n as as Windows CMD mangles the property value, but you can use java @argfile instead.

Just open Windows CMD.EXE to create a config file for the OS style line separator property:

echo -Dline.separator="\n"   > gnu.linesep.args
echo -Dline.separator="\r\n" > windows.linesep.args

Then you can invoke your application on Windows with the line separator behaviour of GNU/Linux:

java @gnu.linesep.args ... etc

You can also make GNU/Linux launch behave with Windows line separator using file:

java @windows.linesep.args ... etc
# which is same as the direct approach mentioned by aioobe:
java -Dline.separator=

See the example test in this answer How can I force Java stdout on windows to use the "\n" line seperator?

\r\n' ... etc

See the example test in this answer How can I force Java stdout on windows to use the "\n" line seperator?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文