在Windows上,使用System.out.println()
打印出\n\r
,而在Unix系统上,您将获得\n
。
有没有办法告诉java你想要使用哪些换行符?
答案 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.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'
}