In Java, ovviamente. Sto scrivendo un programma e l'ho eseguito in ambiente Windows, ma ho bisogno che l'output (.csv) sia fatto in formato Unix. Qualche soluzione facile? Grazie!Esiste un modo per rendere l'output di PrintWriter in formato UNIX?
risposta
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.
Eccellente, grazie! – Monster
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.
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
Ah, capisco. Ottima idea anche. Nel mio caso però (anche se avrei dovuto specificare), sto cercando un approccio globale. Grazie! – Monster
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);
}
}
}
}
Qual è il ragionamento qui :)? –
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
Sfortunatamente questo non impedisce a un altro metodo di modificare contemporaneamente la proprietà senza utilizzare questo blocco. –
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.
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' –
Punto giusto, l'override di println() è un'idea migliore: ho aggiornato il mio codice.La chiamata a 'write' gestisce il blocco. –
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;
}
}
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.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(); } } }
Che cosa si intende con il formato UNIX? Formato finale di linea? – jitter