2010-09-14 18 views
13

Qualcuno ha trovato un modo su come specificare la proprietà Java line.separator all'avvio della VM? Stavo pensando a qualcosa di simile:Impostazione Java VM line.separator

java -Dline.separator="\n" 

Ma questo non interpreta il carattere "\ n" come carattere di avanzamento riga. Qualche idea?

+0

Puoi provare \ r \ n –

risposta

13

Provare a utilizzare java -Dline.separator=$'\n'. Questo dovrebbe fare il trucco, almeno in bash.

Ecco un test-run:

[email protected]:~/tmp$ cat Test.java 
public class Test { 
    public static void main(String[] args) { 
     System.out.println("\"" + System.getProperty("line.separator") + "\""); 
    } 
} 
[email protected]:~/tmp$ javac Test.java && java -Dline.separator=$'\n' Test 
" 
" 
[email protected]:~/tmp$ 

Nota:

L'espressione $'' utilizza la funzionalità di Bash ANSI-C Citando. Espande i caratteri di escape backslash, quindi $'\n' produce un carattere di avanzamento riga (codice ASCII 10), racchiuso tra virgolette singole. Vedere il manuale di Bash, sezione 3.1.2.4 ANSI-C Quoting.

+0

Sì ... ma non dovresti. –

+4

Posso sicuramente vedere come potrebbe essere utile, ad esempio, in uno scenario di test. – aioobe

+0

Grazie, questo lo ha risolto dalla riga di comando. Non funziona ancora all'interno della configurazione di esecuzione di Eclipse IDE, ma non è importante. –

3

Non lo farei se fossi in te. Il separatore di riga è specifico della piattaforma e dovrebbe rimanere tale. Se si desidera scrivere solo file di Windows o solo Linux, definire una costante UNIX_LINE_SEPARATOR da qualche parte e utilizzarla al suo posto.

+2

esattamente.alcune cose non dovrebbero essere cambiate. qualsiasi API che si basa su line.separator con un valore specifico è interrotta. –

+14

Sarei grato se consideri che le altre persone non sono solo stupide ma hanno le loro ragioni. Il mio è che viene chiamato un programma Java da uno script di shell. Lo script di shell ha utilizzato lo stdout dell'app Java e lo elabora ulteriormente. Se si esegue lo script da Cygwin, Java utilizza i linefeed di Windows. Tuttavia, ciò causa problemi nello script. Quindi, mi piacerebbe cambiare il line.separator di default di Javas nel caso sia eseguito da Cygwin. –

+1

prima, potresti aver condiviso questi dettagli nella domanda. In secondo luogo, cosa c'è di così speciale in questo script di shell che non può essere programmato in Java? Non mi sembra ragionevole avere un software java solo per Linux, che ti piace girare con Cygwin. Fornire un file '.bat' (ad esempio Tomcat, ad esempio) o spostare la funzionalità in una classe Java. E infine, non considero nessuno stupido. Ma le persone sono spesso inesperte. – Bozho

4

Per colmare il divario tra le risposte di aioobe e Bozho, vorrei anche sconsigliare l'impostazione del parametro line.separator all'avvio di JVM, in quanto ciò interrompe potenzialmente molti presupposti fondamentali che la JVM e il codice della libreria generano sull'ambiente in esecuzione. Ad esempio, se una libreria da cui si dipende si basa su line.separator per archiviare un file di configurazione in un modo multipiattaforma, hai appena infranto quel comportamento. Sì, è un caso limite, ma questo rende ancora più nefasto quando, da qualche anno a questa parte, si verifica un problema, e ora tutto il codice dipende da questo aggiustamento, mentre le tue librerie lo assumono (correttamente) non lo è.

Detto questo, a volte queste cose non sono sotto il tuo controllo, come quando una libreria si basa su line.separator e non consente in alcun modo di ignorare esplicitamente tale comportamento. In tal caso, sei bloccato a prevalere sul valore, o qualcosa di più doloroso come re-implementare o applicare patch al codice manualmente.

In questi casi limitati, l'è accettabile per ignorare line.separator, ma abbiamo avuto modo di seguire due regole:

  1. minimizzare la portata della sostituzione
  2. Ripristinare l'override non importa quale

Entrambi questi requisiti sono ben serviti da AutoCloseable e dalla sintassi try-with-resources, quindi ho implementato una classe PropertiesModifier che fornisce in modo pulito entrambi.

/** 
* Class which enables temporary modifications to the System properties, 
* via an AutoCloseable. Wrap the behavior that needs your modification 
* in a try-with-resources block in order to have your properties 
* apply only to code within that block. Generally, alternatives 
* such as explicitly passing in the value you need, rather than pulling 
* it from System.getProperties(), should be preferred to using this class. 
*/ 
public class PropertiesModifier implements AutoCloseable { 
    private final String original; 

    public PropertiesModifier(String key, String value) { 
    this(ImmutableMap.of(key, value)); 
    } 

    public PropertiesModifier(Map<String, String> map) { 
    StringWriter sw = new StringWriter(); 
    try { 
     System.getProperties().store(sw, ""); 
    } catch (IOException e) { 
     throw new AssertionError("Impossible with StringWriter", e); 
    } 
    original = sw.toString(); 
    for(Map.Entry<String, String> e : map.entrySet()) { 
     System.setProperty(e.getKey(), e.getValue()); 
    } 
    } 

    @Override 
    public void close() { 
    Properties set = new Properties(); 
    try { 
     set.load(new StringReader(original)); 
    } catch (IOException e) { 
     throw new AssertionError("Impossible with StringWriter", e); 
    } 
    System.setProperties(set); 
    } 
} 

mio caso d'uso era con Files.write(), che è un metodo molto conveniente, tranne che si basa esplicitamente line.separator. Raggomando la chiamata a Files.write() posso chiaramente specificare il separatore di linea che voglio usare, senza rischiare di esporlo a qualsiasi altra parte della mia applicazione (prendere nota ovviamente che questo non è ancora sicuro per i thread).

try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) { 
    Files.write(file, ImmutableList.of(line), Charsets.UTF_8); 
} 
Problemi correlati