In Java, of course. I\'m writing a program and running it under a Windows environment, but I need the output (.csv) to be done in Unix format. Any easy solution? Thanks!
Assuming the formatting issue you refer to is that Windows line breaks are Carriage Return-Line Feed ("\r\n"
) while Unix ones are Line Feed ("\n"
) only, the easiest way to make sure your file uses LF and not CRLF is to eschew println
and instead use print("\n")
to terminate lines.
So instead of:
writer.println("foo,bar,88");
use
writer.print("foo,bar,88\n");
You can just search the relevant files for println
to make sure you catch them all.
I see 2 more options that do not affect the whole system or lead to concurrency proplems like setting the lineSeparator
. I would also declare an enum that represents the line 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 encapsulates the access using reflection to hide PrintWriter internals from clients. E.g. client code should look like this:
PrintWriterFactory.newPrintWriter(someWriter, LineEnding.UNIX);
While the implementation 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 not be static. You can use an interface and multiple implementations if the PrintWriter
implementation changes from one JDK to another and thus you must use another reflection strategy.
Extend PrintWriter and overwrite the println()
method
public 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 on the system properties object, at least if different Printwriters needs different 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);
}
}
}
}
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 the line terminator instead of "\r\n"? Just set the line.separator
system property before you create 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 that sets it for the whole JVM, which isn't ideal, but it may be all you happen to need.
To write a file with unix line endings, override println in a class derived from PrintWriter, and 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 touch any existing println calls you have in your code.