Java改变系统的新行字符

时间:2014-03-27 08:05:50

标签: java windows unix newline text-formatting

在Windows上,使用System.out.println()打印出\n\r,而在Unix系统上,您将获得\n

有没有办法告诉java你想要使用哪些换行符?

7 个答案:

答案 0 :(得分:5)

是的,有一种方法,我只是尝试过。

有一个系统属性line.separator。您可以使用System.setProperty("line.separator", whatever)

进行设置

为了确保它确实导致JVM使用其他分隔符,我实现了以下练习:

    PrintWriter writer = new PrintWriter(new FileWriter("c:/temp/mytest.txt"));
    writer.println("hello");
    writer.println("world");
    writer.close();

我现在在Windows上运行,结果是14个字节长的文件:

03/27/2014  10:13 AM                14 mytest.txt
               1 File(s)             14 bytes
               0 Dir(s)  409,157,980,160 bytes free

然而,当我在代码的开头添加以下行时:

    System.setProperty("line.separator", "\n");

我有14个字节长的文件:

03/27/2014 10:13 AM 14 mytest.txt                1个文件14个字节                0 Dir(s)409,157,980,160字节免费

我用记事本打开了这个文件,该记事本无法将单个\n识别为新行,并且看到了单行文本helloworld而不是2个单独的行。所以,这很有效。

答案 1 :(得分:5)

正如其他人所说,系统属性line.separator包含实际的行分隔符。奇怪的是,其他答案错过了简单的结论:您可以通过在启动时更改该系统属性来覆盖该分隔符。

E.g。如果您在命令行中使用选项-Dline.separator=X运行程序,则会System.out.println(…);X结束该行的有趣行为。

棘手的部分是如何在命令行中指定\n\r等字符。但那是系统/环境特定的而不是Java问题。

答案 2 :(得分:1)

您可以尝试:

String str = "\n\r";
System.out.print("yourString"+str);

但你可以改用: -

System.getProperty("line.separator");

获取line seperator

  

返回依赖于系统的行分隔符字符串。它总是回归   相同的值 - 系统属性的初始值   line.separator。

     

在UNIX系统上,它返回“\ n”;在Microsoft Windows系统上   返回“\ r \ n”。

答案 3 :(得分:1)

Java SE tutorial中所述:

  

要修改现有系统属性集,请使用   System.setProperties。此方法采用具有的Properties对象   已初始化为包含要设置的属性。这种方法   用新集替换整个系统属性集   由Properties对象表示。

     

警告:更改系统   属性是有潜在危险的,应该用   自由裁量权。启动后不会重读许多系统属性   是出于提供信息的目的。改变一些属性可能   有意想不到的副作用。

对于System.out.println(),将使用系统启动时存在的行分隔符。这可能是因为System.lineSeparator()用于终止该行。来自文档:

  

返回依赖于系统的行分隔符字符串。它总是回归   相同的值 - 系统属性的初始值   line.separator。

     

在UNIX系统上,它返回" \ n&#34 ;;在Microsoft Windows系统上   返回" \ r \ n"。

作为Holger pointed out,您需要在启动JVM时覆盖此属性。

答案 4 :(得分:1)

因为接受的答案根本不起作用,正如其他人在我之前指出的那样,并且 JDK 只初始化该值一次,然后再也不会读取该属性,只有一个内部静态字段,所以很明显改变的干净方式该属性是在启动JVM时在命令行中设置。到目前为止,一切都很好。

我写另一个答案的原因是我想提出一种反思的方式来改变这个领域,这对依赖 System.lineSeparator() 的流和作家真的很有效。更新系统属性也没什么坏处,只是字段更重要。

我知道反射是丑陋的,因为 Java 16+ 需要一个额外的 JVM 命令行参数才能允许它,并且只有在 System 的内部结构在 OpenJDK 中没有改变时才有效。但是 FWIW,这是我的解决方案 - 不要在家里这样做,孩子们:

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;

/**
 * 'assert' requires VM parameter '-ea' (enable assert)
 * 'Field.setAccessible' on System requires '--add-opens java.base/java.lang=ALL-UNNAMED' on Java 16+
 */
public class ChangeLineSeparator {
  public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException {
    assert System.lineSeparator().equals("\r\n") : "default Windows line separator should be CRLF";
    Field lineSeparator = System.class.getDeclaredField("lineSeparator");
    lineSeparator.setAccessible(true);
    lineSeparator.set(null, "\n");
    assert System.lineSeparator().equals("\n") : "modified separator should be LF";

    File tempFile = Files.createTempFile(null, null).toFile();
    tempFile.deleteOnExit();
    try (PrintWriter out = new PrintWriter(new FileWriter(tempFile))) {
      out.println("foo");
      out.println("bar");
    }
    assert tempFile.length() == "foo\nbar\n".length() : "unexpected file size";
  }
}

答案 5 :(得分:0)

方法System.lineSeparator()返回系统使用的行分隔符。从文档中指出它使用系统属性line.separator。

答案 6 :(得分:0)

检查 Java 11 实现:

private static void initPhase1() {
    lineSeparator = props.getProperty("line.separator");
}

public static String lineSeparator() {
    return lineSeparator;
}

因此在运行时更改系统属性不会更改 System.lineSeparator()

为此有些项目直接重读系统属性,见我的回答:How to avoid CRLF (Carriage Return and Line Feed) in Logback - CWE 117

唯一可行的选择是在应用启动期间设置系统属性。

对于 Bash,它很简单:java -Dline.separator=$'\n' -jar my.jar

对于 POSIX shell,最好先将该字符保存在某个变量中:

LF='
'

java -Dline.separator="$LF" -jar my.jar

如果你不确定调试它:

printf %s "$LF" | wc -c
1

printf %s "$LF" | od -x
0000000 000a

对于 Gradle 我使用:

tasks.withType(Test).configureEach {
    systemProperty 'line.separator', '\n'
}

bootRun {
    systemProperty 'line.separator', '\n'
}