【问题标题】:Java change system new-line characterJava更改系统换行符
【发布时间】:2014-05-06 01:37:11
【问题描述】:

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

有没有办法告诉java你想用什么换行符?

【问题讨论】:

  • String NEWLINE = "\n\r"; 或任何你想要的,然后是System.out.print("yourString"+NEWLINE);
  • 这是一个可行的解决方法,但你不能明确告诉java你想要定位什么环境吗?

标签: java windows unix newline text-formatting


【解决方案1】:

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

例如如果您在命令行中使用选项-Dline.separator=X 运行程序,您将得到System.out.println(…);X 结尾的有趣行为。

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

【讨论】:

  • 可以指定换行符如下-Dline.separator=$'\n'
  • @Andreas +1。位 $'\n' 用法意味着一个 bash shell,并且还需要设置 IFS=' ' ,否则换行符可能会被视为空格并被丢弃。
【解决方案2】:

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

有一个系统属性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 字节长的文件:

2014 年 3 月 27 日上午 10:13 14 mytest.txt 1 个文件 14 个字节 0 Dir(s) 409,157,980,160 字节空闲

我用记事本打开了这个文件,它不能将单个 \n 识别为新行,并看到单行文本 helloworld 而不是 2 个单独的行。所以,这行得通。

【讨论】:

  • 通过 cywgin 中的od 进行确认。谢谢一堆!
  • +1 如果你快了几分钟,我已经跳过了自己的答案……但是,值得注意的是,一些 JRE 部分缓存了该值,就像 Java 7 java.lang.System.lineSeparator() 一样。要获得一致的行为,应在启动时指定该属性。
  • 我从来没有想过这个问题。我仍然认为这个答案是最好的,但这不会改变 System.out.println() 的行为,它仍然会输出 \r\n
  • 虽然这个答案在技术上是正确的,但我想指出,如果您使用的是 3rd 方库,将系统属性更改为错误的东西可能会引起很多麻烦。另请记住,此更改是 JVM 范围的,因此无论您是否打算,它都会影响在该 JVM 上运行的所有内容。
  • 正如@Andreas 所指出的,您可以使用 -Dline.separator=$'\n'
【解决方案3】:

你可以试试:

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

但你可以改用这个:-

System.getProperty("line.separator");

获取line seperator

返回系统相关的行分隔符字符串。它总是返回 相同的值 - 系统属性的初始值 行分隔符。

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

【讨论】:

  • 好的,所以out.println() 使用这个方法来添加它的换行符。但是有什么方法可以改变属性line.separator 返回的内容吗?告诉 java 你可能正在瞄准另一个平台?
  • 我投了反对票,因为问题询问了如何更改分隔符,而您刚刚提出了如何获取它,但是自从您更新了答案后,我决定将其删除,因为它现在看起来好多了:)
  • @Andreas:- 你可以在代码开头使用System.setProperty("line.separator", "\n");
【解决方案4】:

Java SE tutorial中所述:

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

警告:改变系统 属性具有潜在危险,应与 审慎。许多系统属性在启动后不会重新读取,并且 是为了提供信息。更改某些属性可能 有意想不到的副作用。

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

返回系统相关的行分隔符字符串。它总是返回 相同的值 - 系统属性的初始值 行分隔符。

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

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

【讨论】:

    【解决方案5】:

    因为接受的答案根本不起作用,正如其他人在我之前指出的那样,并且 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";
      }
    }
    

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        检查 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'
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-06-26
          • 1970-01-01
          • 2019-04-12
          • 1970-01-01
          • 1970-01-01
          • 2016-04-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多