2009-06-18 22 views

Respuesta

14

Por "formato Unix" ¿quiere decir usar "\ n" como el terminador de línea en lugar de "\ r \ n"? Simplemente configure la propiedad del sistema line.separator antes de crear el PrintWriter.

Así como una demostración:

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

Por supuesto que establece que para toda la JVM, que no es lo ideal, pero puede ser todo lo que sucede necesitar.

+0

Excelente, gracias! – Monster

3

Suponiendo que el problema de formato que se refieren a es que los saltos de línea de Windows son de carro y avance de línea de retorno ("\r\n"), mientras que los de Unix son salto de línea ("\n") solamente, la forma más fácil de asegurarse de que su archivo utiliza LF, y CRLF es para evitar println y en su lugar usar print("\n") para terminar líneas.

Así que en lugar de:

writer.println("foo,bar,88"); 

uso

writer.print("foo,bar,88\n"); 

Usted puede simplemente buscar en los archivos pertinentes para println para asegurarse de que todos ellos captura.

+0

La diferencia entre este enfoque y el de Jon Skeet es que el suyo es global, pero requiere menos cambios. Siempre y cuando esté seguro de que no le importa que todo en su programa vaya a utilizar \ n en su lugar o \ r \ n, simplemente establecer line.separator es probablemente más fácil. – Zarkonnen

+0

Ah, ya veo. Excelente idea también Sin embargo, en mi caso (aunque debería haberlo especificado), estoy buscando un enfoque global. ¡Gracias! – Monster

2

Un programador paranoico se sincronizaría en el objeto de propiedades del sistema, al menos si diferentes Printwriters necesitan diferentes tipos de terminadores de línea.

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

¿Cuál es el razonamiento aquí :)? –

+2

Para asegurarse de que realmente obtendrá la propiedad que acaba de establecer, a menos que esté ejecutando en un subproceso, o siempre utilizará el mismo terminador de línea, y que nunca va a cambiar. – KarlP

+0

Desafortunadamente, esto no impide que otro método cambie la propiedad simultáneamente sin usar este bloqueo. –

8

Para escribir un archivo con los finales de línea Unix, anulan println en una clase derivada de PrintStream, y el uso de impresión con \ 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(); 

Esto evita tener que tocar ninguna println llamadas existentes que tiene en su código.

+0

No, solo debe sobrescribir 'println()'. Todos los demás métodos de impresión (por ejemplo, 'println (String)', 'println (int)', etc. se documentan como impresión de datos y luego se llama a 'println()'. Además, debe sincronizar en la variable protegida 'lock' –

+0

Punto justo, reemplazar println() es una mejor idea. He actualizado mi código. La llamada a 'write' maneja el bloqueo. –

1

Veo 2 opciones más que no afectan a todo el sistema ni conducen a los valores de concurrencia como configurar el lineSeparator. También declararía una enumeración que representa los finales de línea.

enum LineEnding { 
    UNIX("\n"), DOS("\r\n"); 

    private String lineSeparator; 

    LineEnding(String lineSeparator) { 
    this.lineSeparator = lineSeparator; 
    } 

    public String getLineSeparator() { 
    return lineSeparator; 
    } 
} 
  1. Establecer la lineSeperator utilizando la reflexión.

    Debe crear una fábrica que encapsule el acceso utilizando reflejo para ocultar las partes internas de PrintWriter de los clientes. P.ej. código de cliente debe tener este aspecto:

    PrintWriterFactory.newPrintWriter(someWriter, LineEnding.UNIX); 
    

    Mientras que la aplicación podría tener este aspecto:

    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: La fábrica no debe ser estática. Puede utilizar una interfaz y varias implementaciones si la implementación de PrintWriter cambia de un JDK a otro y, por lo tanto, debe usar otra estrategia de reflexión.

  2. Extender PrintStream y sobrescribir el método println()

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