Java change system new-line character
Asked Answered
H

8

10

On Windows, using System.out.println() prints out \n\r while on a Unix system you would get \n.

Is there any way to tell java what new-line characters you want to use?

Halflight answered 27/3, 2014 at 8:5 Comment(3)
String NEWLINE = "\n\r"; or whatever you want, followed by System.out.print("yourString"+NEWLINE);Bethezel
That's a workaround that does work but can't you explicitly tell java what environment you want to target?Halflight
Changing line.separator after VM start is not officially supported. All attempts to report this as a bug were closed AFAICT. bugs.openjdk.org/browse/… N.B. there's one that's still open, but you should read the comments bugs.openjdk.org/browse/JDK-8294410Tallage
H
8

As already stated by others, the system property line.separator contains the actual line separator. Strangely, the other answers missed the simple conclusion: you can override that separator by changing that system property at startup time.

E.g. if you run your program with the option -Dline.separator=X at the command line you will get the funny behavior of System.out.println(…); ending the line with an X.

The tricky part is how to specify characters like \n or \r at the command line. But that’s system/environment specific and not a Java question anymore.

Harpsichord answered 27/3, 2014 at 8:23 Comment(2)
you can specify newline as follows -Dline.separator=$'\n'Halflight
@Halflight +1. bit the $'\n' usage implies a bash shell, and that requires IFS=' ' also to be set, otherwise the newline may be treated as whitespace and discarded.Pentha
S
7

Yes, there is a way and I've just tried it.

There is a system property line.separator. You can set it using System.setProperty("line.separator", whatever)

To be sure that it indeed causes JVM to use other separator I implemented the following exercise:

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

I am running on windows now, so the result was 14 bytes long file:

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

However when I added the following line to the beginning of my code:

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

I got 14 bytes long file:

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

I opened this file with notepad that does not recognize single \n as a new line and saw one-line text helloworld instead of 2 separate lines. So, this works.

Skintight answered 27/3, 2014 at 8:19 Comment(9)
Confirmed by piping through to od in cywgin. Thanx a bunch!Halflight
+1 If you were a few minutes faster I had skipped writing my own answer… However, it’s worth noting that some JRE parts cache that value, like the Java 7 java.lang.System.lineSeparator() does. To get a consistent behavior, that property should be specified at startup time.Harpsichord
I never though about this actually. I still think this answer is the best however, this does not change the behaviour of System.out.println() which will still output \r\nHalflight
While this answer is technically correct, I'd like to point out that changing the system property to something that is wrong can potentially cause a lot of headaches, if you're using 3rd party libraries. Also keep in mind that this change is JVM-wide, so it will effect everything running on that JVM, whether you intend to or not.Superfluid
@Holger, sure, you are right. Using -Dline.separator is preferable. I however do not know how to pass \n from shell... I was just too lazy to try this.Skintight
@Andreas: As said, at some places that property is cached. In case of System.out.println() it’s the class BufferedWriter which does that caching. Specifying the property at the command line works.Harpsichord
as pointed out by @Andreas, you can use -Dline.separator=$'\n'Pentha
This is not working on Java 14. I did not check backwards to previous Java versions when it started to break, but unless the property is set on the command line, it definitely has not effect for me, neither with streams nor with writers.Cata
BTW, does anyone know how to do this on Windows in IntelliJ IDEA run configurations? I found no way to escape a newline character in there.Cata
C
2

Because the accepted answer simply does not work, as others pointed out before me, and the JDK only initialises the value once and then never reads the property anymore, only an internal static field, it became clear that the clean way to change the property is to set it on the command line when starting the JVM. So far, so good.

The reason I am writing yet another answer is that I want to present a reflective way to change the field, which really works with streams and writers relying on System.lineSeparator(). It does not hurt to update the system property, too, but the field is more important.

I know that reflection is ugly, as of Java 16+ needs an extra JVM command line parameter in order to allow it, and only works as long as the internals of System do not change in OpenJDK. But FWIW, here is my solution - don't do this at home, kids:

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";
  }
}
Cata answered 3/5, 2021 at 3:37 Comment(0)
B
2

Windows cmd: Credit jeb at https://superuser.com/a/1519790 for a technique to specify a line-feed character in a parameter using a cmd variable. This technique can be used to specify the java line.separator.

Here's a sample javalf.cmd file

@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

Here's a short test progam.

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()));
  }
}

On Windows, java ReadLineSeparator produces

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

.\javalf.cmd ReadLineSeparator produces

{LINE FEED (LF)}
Blithering answered 26/3, 2022 at 17:15 Comment(0)
C
1

You may try with:

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

but you can instead use this:-

System.getProperty("line.separator");

to get the line seperator

Returns the system-dependent line separator string. It always returns the same value - the initial value of the system property line.separator.

On UNIX systems, it returns "\n"; on Microsoft Windows systems it returns "\r\n".

Cyclamate answered 27/3, 2014 at 8:10 Comment(3)
Ok so out.println() uses this method to add it's linebreak. But is there some way to change what the property line.separator returns? Tell java that you are targeting another platform maybe?Halflight
I downvoted becuase the question asked how to change the seperator, and you had just put how to get it, however since you updated your answer I decided to remove it as it looks a lot better now :)Guacin
@Andreas:- You may use the System.setProperty("line.separator", "\n"); at the beginning of your code then!Cyclamate
B
1

As stated in the Java SE tutorial:

To modify the existing set of system properties, use System.setProperties. This method takes a Properties object that has been initialized to contain the properties to be set. This method replaces the entire set of system properties with the new set represented by the Properties object.

Warning: Changing system properties is potentially dangerous and should be done with discretion. Many system properties are not reread after start-up and are there for informational purposes. Changing some properties may have unexpected side-effects.

In the case of System.out.println(), the line separator that existed on system startup will be used. This is probably because System.lineSeparator() is used to terminate the line. From the documentation:

Returns the system-dependent line separator string. It always returns the same value - the initial value of the system property line.separator.

On UNIX systems, it returns "\n"; on Microsoft Windows systems it returns "\r\n".

As Holger pointed out, you need to overwrite this property at startup of the JVM.

Bethezel answered 27/3, 2014 at 8:38 Comment(0)
L
0

The method System.lineSeparator() returns the line separator used by the system. From the documentation it specifies that it uses the system property line.separator.

Lanate answered 27/3, 2014 at 8:11 Comment(0)
C
0

Checked Java 11 implementation:

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

public static String lineSeparator() {
    return lineSeparator;
}

So altering system property at runtime doesn't change System.lineSeparator().

For this reason some projects re-read system property directly, see my answer: How to avoid CRLF (Carriage Return and Line Feed) in Logback - CWE 117

The only viable option is to set system property during app startup.

For Bash it is as simple as: java -Dline.separator=$'\n' -jar my.jar.

For POSIX shell it is better to save that character in some variable first:

LF='
'

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

If you are not sure debug it:

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

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

For Gradle I use:

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

bootRun {
    systemProperty 'line.separator', '\n'
}
Critta answered 23/3, 2021 at 15:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.