[ACCEPTED]-Is there a way to make PrintWriter output to UNIX format?-unix
To write a file with unix line endings, override 4 println in a class derived from PrintWriter, and 3 use print with \n.
PrintWriter out = new PrintWriter("testFile") {
@Override
public void println() {
write('\n');
}
};
out.println("This file will always have unix line endings");
out.println(41);
out.close();
This avoids having to 2 touch any existing println calls you have 1 in your code.
Note: as reported in comments, the approach given below breaks in JDK 9+. Use the approach in James H.'s answer.
By "Unix format" do you mean using "\n" as 5 the line terminator instead of "\r\n"? Just 4 set the line.separator
system property before you create 3 the PrintWriter.
Just as a demo:
import java.io.*;
public class Test
{
public static void main(String[] args)
throws Exception // Just for simplicity
{
System.setProperty("line.separator", "xxx");
PrintWriter pw = new PrintWriter(System.out);
pw.println("foo");
pw.println("bar");
pw.flush();
}
}
Of course 2 that sets it for the whole JVM, which isn't 1 ideal, but it may be all you happen to need.
Assuming the formatting issue you refer 7 to is that Windows line breaks are Carriage 6 Return-Line Feed ("\r\n"
) while Unix ones are 5 Line Feed ("\n"
) only, the easiest way to make 4 sure your file uses LF and not CRLF is to 3 eschew println
and instead use print("\n")
to terminate lines.
So 2 instead of:
writer.println("foo,bar,88");
use
writer.print("foo,bar,88\n");
You can just search the relevant 1 files for println
to make sure you catch them all.
I see 2 more options that do not affect 12 the whole system or lead to concurrency 11 proplems like setting the lineSeparator
. I would also 10 declare an enum that represents the line 9 endings.
enum LineEnding {
UNIX("\n"), DOS("\r\n");
private String lineSeparator;
LineEnding(String lineSeparator) {
this.lineSeparator = lineSeparator;
}
public String getLineSeparator() {
return lineSeparator;
}
}
Set the
lineSeperator
using reflection.You should create a factory that 8 encapsulates the access using reflection 7 to hide PrintWriter internals from clients. E.g. client 6 code should look like this:
PrintWriterFactory.newPrintWriter(someWriter, LineEnding.UNIX);
While the implementation 5 could look like this:
public class PrintWriterFactory { private static final Field lineSeparatorField; static { try { lineSeparatorField = PrintWriter.class.getDeclaredField("lineSeparator"); lineSeparatorField.setAccessible(true); } catch (NoSuchFieldException e) { throw new IllegalStateException("java.io.PrintWriter implementation changed. Unable to determine lineSeparator field.", e); } } public static PrintWriter newPrintWriter(Writer writer, LineEnding lineEnding) { PrintWriter printWriter = new PrintWriter(writer); try { lineSeparatorField.set(printWriter, lineEnding.getLineSeparator()); } catch (IllegalAccessException e) { throw new IllegalStateException("Can't set line ending", e); } return printWriter; } }
PS: The factory must 4 not be static. You can use an interface 3 and multiple implementations if the
PrintWriter
implementation 2 changes from one JDK to another and thus 1 you must use another reflection strategy.Extend PrintWriter and overwrite the
println()
methodpublic class LineEndingPrintWriter extends PrintWriter { protected boolean autoFlush = false; private LineEnding lineEnding; public LineEndingPrintWriter(Writer out, LineEnding lineEnding) { this(out, false, lineEnding); } public LineEndingPrintWriter(Writer out, boolean autoFlush, LineEnding lineEnding) { super(out, autoFlush); this.autoFlush = autoFlush; this.lineEnding = lineEnding; } public LineEndingPrintWriter(OutputStream out, LineEnding lineEnding) { this(out, false, lineEnding); } public LineEndingPrintWriter(OutputStream out, boolean autoFlush, LineEnding lineEnding) { super(out, autoFlush); this.autoFlush = autoFlush; this.lineEnding = lineEnding; } protected void ensureOpen() throws IOException { if (out == null) throw new IOException("Stream closed"); } public void println() { // Method body taken from java.io.PrintWriter.println(); try { synchronized (lock) { ensureOpen(); out.write(lineEnding.getLineSeparator()); if (autoFlush) { out.flush(); } } } catch (InterruptedIOException e) { Thread.currentThread().interrupt(); } catch (IOException e) { setError(); } } }
A paranoid programmer would synchronize 3 on the system properties object, at least 2 if different Printwriters needs different 1 types of line terminators.
public static PrintWriter createPrintWriter(OutputStreamWriter out, boolean autoflush){
Properties props = System.getProperties();
synchronized (props) {
Object old = null;
try {
old = props.setProperty("line.separator", "\n");
return new PrintWriter(out, autoflush);
} finally {
if( old != null ) {
props.put("line.separator", old);
}
}
}
}
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.