2009-06-18 1 views

risposta

14

Per "formato Unix" si intende l'utilizzo di "\ n" come terminatore di riga anziché "\ r \ n"? Basta impostare la proprietà di sistema line.separator prima di creare PrintWriter.

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

Certo che lo per tutta la JVM, che non è ideale, ma può essere tutto quello che capita di bisogno.

+0

Eccellente, grazie! – Monster

3

ipotizzando l'emissione di formattazione si fa riferimento a è che le interruzioni di linea Windows sono Carriage Return-Line Feed ("\r\n"), mentre quelli Unix linea di alimentazione ("\n") solo, il modo più semplice per assicurarsi che il file utilizza LF e non CRLF è per evitare println e utilizzare invece print("\n") per terminare le righe.

Così, invece di:

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

uso

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

Si può solo cercare i file rilevanti per println per essere sicuri di catturarli tutti.

+0

La differenza tra questo approccio e quello di Jon Skeet è che il suo è globale, ma richiede meno modifiche. Finché sei sicuro che non ti interessi che tutto nel tuo programma userà invece \ n o \ r \ n, impostare semplicemente line.separator è probabilmente più semplice. – Zarkonnen

+0

Ah, capisco. Ottima idea anche. Nel mio caso però (anche se avrei dovuto specificare), sto cercando un approccio globale. Grazie! – Monster

2

Un programmatore paranoico dovrebbe sincronizzarsi sull'oggetto delle proprietà di sistema, almeno se diversi Printwriter necessitano di diversi tipi di terminatori di linea.

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

Qual è il ragionamento qui :)? –

+2

Per assicurarti che otterrai effettivamente la proprietà che hai appena impostato, a meno che tu non stia correndo in un thread, o userai sempre lo stesso terminatore di riga, e questo non cambierà mai. – KarlP

+0

Sfortunatamente questo non impedisce a un altro metodo di modificare contemporaneamente la proprietà senza utilizzare questo blocco. –

8

Per scrivere un file con fine riga UNIX, override println in una classe derivata da PrintWriter, e utilizzare Print 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(); 

Questo evita di dover toccare println esistenti impone che avete nel vostro codice.

+0

No, dovresti semplicemente sovrascrivere 'println()'. Tutti gli altri metodi println (ad esempio 'println (String)', 'println (int)', ecc. Sono documentati come stampa dei dati e quindi chiamata 'println()'. Inoltre, dovresti eseguire la sincronizzazione sulla variabile protetta 'lock' –

+0

Punto giusto, l'override di println() è un'idea migliore: ho aggiornato il mio codice.La chiamata a 'write' gestisce il blocco. –

1

Vedo 2 ulteriori opzioni che non influiscono sull'intero sistema o portano a giochi di concorrenza come l'impostazione dello lineSeparator. Vorrei anche dichiarare un enum che rappresenta le terminazioni di linea.

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

    private String lineSeparator; 

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

    public String getLineSeparator() { 
    return lineSeparator; 
    } 
} 
  1. Impostare la lineSeperator utilizzando la riflessione.

    È necessario creare una fabbrica che incapsuli l'accesso utilizzando il riflesso per nascondere gli interni di PrintWriter dai client. Per esempio. codice client dovrebbe essere così:

    PrintWriterFactory.newPrintWriter(someWriter, LineEnding.UNIX); 
    

    Mentre l'attuazione potrebbe assomigliare a questo:

    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 fabbrica non deve essere statico. È possibile utilizzare un'interfaccia e più implementazioni se l'implementazione di PrintWriter passa da un JDK all'altro e quindi è necessario utilizzare un'altra strategia di riflessione.

  2. Estendere PrintWriter e sovrascrivere il metodo di 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(); 
        } 
        } 
    }