Suppose I have a string, which consists of a few lines:
aaa\nbbb\nccc\n (in Linux) or aaa\r\nbbb\r\nccc (in Windows)
I need to add character # to every line in the string as follows:
#aaa\n#bbb\n#ccc (in Linux) or #aaa\r\n#bbb\r\n#ccc (in Windows)
What is the easiest and portable (between Linux and Windows) way to do it Java ?
Use the line.separator system property
String separator = System.getProperty("line.separator") + "#"; // concatenate the character you want
String myPortableString = "#aaa" + separator + "ccc";
These properties are described in more detail here.
If you open the source code for PrintWriter, you'll notice the following constructor:
public PrintWriter(Writer out,
boolean autoFlush) {
super(out);
this.out = out;
this.autoFlush = autoFlush;
lineSeparator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}
It's getting (and using) the system specific separator to write to an OutputStream.
You can always set it at the property level
System.out.println("ahaha: " + System.getProperty("line.separator"));
System.setProperty("line.separator", System.getProperty("line.separator") + "#"); // change it
System.out.println("ahahahah:" + System.getProperty("line.separator"));
prints
ahaha:
ahahahah:
#
All classes that request that property will now get {line.separator}#
I don't know what exactly you are using, but PrintWriter's printf methods lets you write formatted strings. Withing the string you can use the %n format specifier which will output the platform specific line separator.
System.out.printf("first line%nsecond line");
The output:
first line
second line
(System.out is a PrintStream which also supports this).
As of Java 7 (also noted here) you can also use the method:
System.lineSeparator()
which is the same as:
System.getProperty("line.separator")
to get the system-dependent line separator string.
The description of the method from the official JavaDocs is quoted below:
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".
Related
I want to print a string to a text using out.print but the \n in the string are not working.
Here is the code:
import java.io.PrintWriter;
public class LetterRevisited{
public static void main(String[] args)throws Exception
{
PrintWriter out = new PrintWriter("Test.txt");
out.println("This is the first line\n" +
"This is the second line" );
out.close();
}
}
But in the saved file no new line is created, all the lines are after each other.
Any idea how to fix this? (beside adding out.println to all lines.)
Edit: I compile and run the code with windows command prompt and open the file with notepad.
Different platforms use different line separators.
Windows use \r\n
Unix-like platforms use \n
Mac now uses \n too, but it used to use \r.
(You can see more information and variants here)
You can get your "local" line separator by using
System.getProperty("line.separator")
e.g.
out.println("Hello" + System.getProperty("line.separator") + "World");
However, it is easier to use %n in a string formatter:
out.printf("Hello%nWorld%n");
If you are targeting a particular platform, you can just use the literal.
If you are using Java 7 then you can use System.lineSeparator()..see if this helps. For older versions of Java you can use - System.getProperty("line.separator")
Example :
System.out.println(System.lineSeparator()+"This is the second line");
What should I see when I use the following?
System.out.println("LineSeperator1: "+System.getProperty("line.separator"));
System.out.println("LineSeperator2: "+System.lineSeparator());
I get the following back:
LineSeperator1:
LineSeperator2:
Is it empty? invisible? shouldn there be something like \r or \n?
I use windows 7, eclipse and jdk 1.8.
As you expect, the line separator contains special characters such as '\r' or '\n' that denote the end of a line. However, although they would be written in Java source code with those backslash escape sequences, they do not appear that way when printed. The purpose of a line separator is to separate lines, so, for example, the output of
System.out.println("Hello"+System.lineSeparator()+"World");
is
Hello
World
rather than, say
Hello\nWorld
You can even see this in the output of your code: the output of
System.out.println("LineSeperator1: "+System.getProperty("line.separator"));
had an extra blank line before the output of the next statement, because there was a line separator from System.getProperty("line.separator") and another from the use of println.
If you really want to see what the escaped versions of the line separators look like, you can use escapeJava from Apache Commons. For example:
import org.apache.commons.lang3.StringEscapeUtils;
public class LineSeparators {
public static void main(String[] args) {
String ls1 = StringEscapeUtils.escapeJava(System.getProperty("line.separator"));
System.out.println("LineSeperator1: "+ls1);
String ls2 = StringEscapeUtils.escapeJava(System.lineSeparator());
System.out.println("LineSeperator2: "+ls2);
}
}
On my system, this outputs
LineSeparator1: \n
LineSeparator2: \n
Note that I had to run it in the same folder as the .jar file from the Apache download, compiling and running with these commands
javac -cp commons-lang3-3.4.jar LineSeparators.java
java -cp commons-lang3-3.4.jar:. LineSeparators
Printing something afterwards will show the effect:
System.out.println("a" + System.lineSeparator() + "b");
Gives
a
b
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?
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.
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.
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";
}
}
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".
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.
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)}
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.
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'
}
I have a text file with 1000 lines in the following format:
19 x 75 Bullnose Architrave/Skirting £1.02
I am writing a method that reads the file line by line in - This works OK.
I then want to split each string using the "£" as a deliminater & write it out to
an ArrayList<String> in the following format:
19 x 75 Bullnose Architrave/Skirting, Metre, 1.02
This is how I have approached it (productList is the ArrayList, declared/instantiated outside the try block):
try{
br = new BufferedReader(new FileReader(aFile));
String inputLine = br.readLine();
String delim = "£";
while (inputLine != null){
String[]halved = inputLine.split(delim, 2);
String lineOut = halved[0] + ", Metre, " + halved[1];//Array out of bounds
productList.add(lineOut);
inputLine = br.readLine();
}
}
The String is not splitting and I keep getting an ArrayIndexOutOfBoundsException. I'm not very familiar with regex. I've also tried using the old StringTokenizer but get the same result.
Is there an issue with £ as a delim or is it something else? I did wonder if it is something to do with the second token not being read as a String?
Any ideas would be helpful.
Here are some of the possible causes:
The encoding of the file doesn't match the encoding that you are using to read it, and the "pound" character in the file is getting "mangled" into something else.
The file and your source code are using different pound-like characters. For instance, Unicode has two code points that look like a "pound sign" - the Pound Sterling character (00A3) and the Lira character (2084) ... then there is the Roman semuncia character (10192).
You are trying to compile a UTF-8 encoded source file without tell the compiler that it is UTF-8 encoded.
Judging from your comments, this is an encoding mismatch problem; i.e. the "default" encoding being used by Java doesn't match the actual encoding of the file. There are two ways to address this:
Change the encoding of the file to match Java's default encoding. You seem to have tried that and failed. (And it wouldn't be the way I'd do this ...)
Change the program to open the file with a specific (non default) encoding; e.g. change
new FileReader(aFile)
to
new FileReader(aFile, encoding)
where encoding is the name of the file's actual character encoding. The names of the encodings understood by Java are listed here, but my guess is that it is "ISO-8859-1" (aka Latin-1).
This is probably a case of encoding mismatch. To check for this,
Print delim.length and make sure it is 1.
Print inputLine.length and make sure it is the right value (42).
If one of them is not the expected value then you have to make sure you are using UTF-8 everywhere.
You say delim.length is 1, so this is good. On the other hand if inputLine.length is 34, this is very wrong. For "19 x 75 Bullnose Architrave/Skirting £1.02" you should get 42 if all was as expected. If your file was UTF-8 encoded but read as ISO-8859-1 or similar you would have gotten 43.
Now I am a little at a loss. To debug this you could print individually each character of the string and check what is wrong with them.
for (int i = 0; i < inputLine.length; i++)
System.err.println("debug: " + i + ": " + inputLine.charAt(i) + " (" + inputLine.codePointAt(i) + ")");
Many thanks for all your replies.
Specifying the encoding within the read & saving the original text file as UTF -8 has worked.
However, the experience has taught me that delimiting text using "£" or indeed other characters that may have multiple representations in different encodings is a poor strategy.
I have decided to take a different approach:
1) Find the last space in the input string & replace it with "xxx" or similar.
2) Split this using the delimiter "xxx." which should split the strings & rip out the "£".
3) Carry on..
So, I've got the following code to write to a file:
Formatter output = ....... // Creating the formatter works, writes to appropriate file.
output.format("%d\n", records.length);
for(GradeRecord gR:records)
{
output.format(gR.toString() + "\n");
}
Only problem is, the output doesn't have newline characters.
Doesn't work if I replace "\n" with "\r", either.
...I don't know why this doesn't work. Output is created and writes correctly. (I see the file created and everything is written in it, except for newline characters.)
you can use the format "%n" to output the platform specific newline using a formatter.
You want to use the correct line break string regardless of what platform it's being run on. You can do this dynamically using
String newline = System.getProperty("line.separator");
So you can later do
output.format(gR.toString() + newline);
You can try using \\n instead of \n