Tutorial :Is there a way to make PrintWriter output to UNIX format?



Question:

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!


Solution:1

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.


Solution:2

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.


Solution:3

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.


Solution:4

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


Solution:5

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;    }  }  
  1. 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.

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

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »