2009-06-18 5 views

Répondre

14

Par "format Unix", voulez-vous dire "\ n" comme terminaison de ligne au lieu de "\ r \ n"? Définissez simplement la propriété système line.separator avant de créer le PrintWriter.

Tout comme une démonstration:

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

Bien sûr qu'il fixe pour la machine virtuelle Java ensemble, ce qui est pas idéal, mais il peut être tout ce que vous arrive d'avoir besoin.

+0

Excellent, merci! – Monster

3

En supposant que la question de formatage vous faites référence à est que les sauts de ligne Windows sont transport RSS retour ligne ("\r\n") tandis que les Unix sont ligne Feed ("\n") seulement, la meilleure façon de vous assurer que votre fichier utilise LF et non CRLF est pour éviter println et à la place utiliser print("\n") pour terminer les lignes.

Ainsi, au lieu de:

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

utilisation

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

Vous pouvez simplement rechercher les fichiers pertinents pour println pour vous assurer que vous les attraper tous.

+0

La différence entre cette approche et Jon Skeet est que son approche est globale, mais nécessite moins de changements. Tant que vous êtes sûr que vous ne vous souciez pas du fait que tout ce que vous utilisez dans votre programme utilise plutôt \ n ou \ r \ n, il est probablement plus facile de définir line.separator. – Zarkonnen

+0

Ah, je vois. Excellente idée aussi. Dans mon cas cependant (bien que j'aurais dû préciser), je suis à la recherche d'une approche globale. Merci! – Monster

2

Un programmeur paranoïaque se synchroniserait sur l'objet de propriétés système, au moins si différents Printwriters avaient besoin de différents types de terminaisons de ligne.

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

Quel est le raisonnement ici :)? –

+2

Pour vous assurer que vous obtiendrez effectivement la propriété que vous venez de définir, sauf si vous exécutez dans un thread, ou utiliserez toujours le même terminateur de ligne, et cela ne va jamais changer. – KarlP

+0

Malheureusement cela n'empêche pas une autre méthode de changer simultanément la propriété sans utiliser ce verrou. –

8

Pour écrire un fichier avec les fins de ligne unix, substituez println dans une classe dérivée de PrintWriter et d'imprimer, avec \ 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(); 

Ceci évite d'avoir à toucher les appels println existants dans votre code.

+0

Non, vous devriez simplement surcharger 'println()'. Toutes les autres méthodes println (par exemple 'println (String)', 'println (int)', etc. sont documentées comme l'impression des données, puis l'appel 'println()' .En outre, vous devez synchroniser sur la variable protégée 'lock' –

+0

Le point juste, écrasant println() est une meilleure idée J'ai mis à jour mon code L'appel de 'write' gère le verrou. –

1

Je vois 2 autres options qui n'affectent pas le système entier ou qui mènent à des problèmes de simultanéité comme le réglage du lineSeparator. Je voudrais également déclarer une énumération qui représente les fins de ligne.

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

    private String lineSeparator; 

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

    public String getLineSeparator() { 
    return lineSeparator; 
    } 
} 
  1. Réglez le lineSeperator utilisant la réflexion.

    Vous devez créer une fabrique qui encapsule l'accès à l'aide de la réflexion pour masquer les composants internes PrintWriter des clients. Par exemple. code client devrait ressembler à ceci:

    PrintWriterFactory.newPrintWriter(someWriter, LineEnding.UNIX); 
    

    Alors que la mise en œuvre pourrait ressembler à ceci:

    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: L'usine ne doit pas être statique. Vous pouvez utiliser une interface et plusieurs implémentations si l'implémentation PrintWriter passe d'un JDK à un autre et vous devez donc utiliser une autre stratégie de réflexion.

  2. Étendre PrintWriter et remplacer la méthode 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(); 
        } 
        } 
    } 
    
Questions connexes