unix Java变更系统换行字符

z3yyvxxp  于 2022-11-04  发布在  Unix
关注(0)|答案(8)|浏览(197)

在Windows系统上,使用System.out.println()会打印出\n\r,而在Unix系统上,则会打印出\n
有没有办法告诉java你想使用什么换行字符?

mrfwxfqh

mrfwxfqh1#

正如其他人已经指出的那样,系统属性line.separator包含实际的行分隔符。奇怪的是,其他人的回答忽略了一个简单的结论:您可以通过在启动时更改系统属性来覆盖该分隔符。
例如,如果您在命令行中使用选项-Dline.separator=X运行程序,您将得到System.out.println(…);X结尾这一行的有趣行为。
棘手的部分是如何在命令行中指定\n\r这样的字符,但这是特定于系统/环境的,不再是Java问题。

h22fl7wq

h22fl7wq2#

是的,有一个办法,我刚刚试过了。
有一个系统属性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个目录409,157,980,160字节可用
我用记事本打开了这个文件,记事本不能将单个\n识别为新行,看到的是单行文本helloworld,而不是两个单独的行。

yduiuuwa

yduiuuwa3#

您可以尝试:

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

但你可以用这个代替:-

System.getProperty("line.separator");

以取得行分隔符号
返回与系统相关的行分隔符字符串。它总是返回相同的值-系统属性line. separator的初始值。
在UNIX系统上,它返回“\n”;在Microsoft Windows系统上,它会传回“\r\n”。

hpcdzsge

hpcdzsge4#

Java SE tutorial中所述:
若要修改现有的系统属性集,请使用System. setProperties。此方法采用已初始化为包含要设置的属性的Properties对象。此方法使用Properties对象表示的新属性集替换整个系统属性集。

**警告:**更改系统属性有潜在危险,应谨慎执行。许多系统属性在启动后不会重新读取,它们仅用于提供信息。更改某些属性可能会产生意外的副作用。

System.out.println()的情况下,将使用系统启动时存在的行分隔符。这可能是因为System.lineSeparator()用于终止该行。请参阅文档:
返回与系统相关的行分隔符字符串。它总是返回相同的值-系统属性line. separator的初始值。
在UNIX系统上,它返回“\n”;在Microsoft Windows系统上,它会传回“\r\n”。
正如Holger所指出的,您需要在JVM启动时覆盖此属性。

ar7v8xwq

ar7v8xwq5#

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

anhgbhbe6#

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

vawmfj5a

vawmfj5a7#

已检查Java 11实作:

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

public static String lineSeparator() {
    return lineSeparator;
}

因此,在运行时更改系统属性不会更改System.lineSeparator()
为此有些项目直接重读系统属性,参见我的解答:如何避免在Logback中出现CRLF(回车和换行)- 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'
}
zlhcx6iw

zlhcx6iw8#

Windows命令:https://superuser.com/a/1519790的jeb提供了一种使用cmd变量在参数中指定换行字符的技术,该技术可用于指定java line.separator。
下面是一个javalf.cmd文件示例

@echo off

REM define variable %\n% to be the linefeed character
(set \n=^^^

^

)

REM Start java using the value of %\n% as the line.separator System property
java -Dline.separator=%\n% %1 %2 %3 %4 %5 %6 %7 %8 %9

这里有一个简短的测试程序。

public class ReadLineSeparator {
  public static void main(String... ignore) {
    System.out.println(System.lineSeparator().chars()
                       .mapToObj(c -> "{"+Character.getName(c)+"}")
                       .collect(java.util.stream.Collectors.joining()));
  }
}

在Windows上,java ReadLineSeparator会产生

{CARRIAGE RETURN (CR)}{LINE FEED (LF)}

.\javalf.cmd ReadLineSeparator产生

{LINE FEED (LF)}

相关问题