2010-09-14 3 views
13

Кто-нибудь нашел способ указать свойство Java line.separator при запуске VM? Я думал о чем-то вроде этого:Настройка Java VM line.separator

Но это не интерпретирует символ «\ n» как символ перевода строки. Есть идеи?

+0

Вы можете попробовать –

ответ

13

Попробуйте использовать java -Dline.separator=$'\n'. Это должно сделать трюк, по крайней мере, в bash.

Вот тест-трасса:

[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$ 

Примечание:

Выражение $'' использует Баш функция ANSI-C Цитирование. Он расширяет символы с обратным слэшем, поэтому $'\n' создает символ линии (ASCII-код 10), заключенный в одинарные кавычки. См. Руководство пользователя Bash, раздел 3.1.2.4 ANSI-C Quoting.

+0

Да ... но вы не должны. –

+4

Я могу определенно увидеть, как это может быть полезно, например, в тестовом сценарии. – aioobe

+0

Спасибо, что решил это из командной строки. Он по-прежнему не работает из конфигурации запуска Eclipse IDE, но это не важно. – 2010-09-14 14:17:33

3

Я бы этого не сделал, если бы был вами. Разделитель строк является специфичным для платформы и должен оставаться таким. Если вы хотите писать файлы только для Windows или только для Linux, определите константу UNIX_LINE_SEPARATOR и используйте ее вместо этого.

+2

точно.некоторые вещи не должны меняться. любой api, который полагается на line.separator, имеющий определенное значение, сломан –

+14

Я бы оценил, если вы считаете, что другие люди не просто глупы, но имеют свои причины. Моя, что Java-программа вызывается из сценария оболочки. Сценарий оболочки использовал stdout приложения Java и обрабатывает его дальше. Если вы запустите этот скрипт из Cygwin, Java использует линейные переводы Windows. Однако это вызывает проблемы в скрипте. Следовательно, я хотел бы изменить Javas default line.separator в случае, если он запускается из Cygwin. – 2010-09-14 13:36:53

+1

во-первых, вы могли бы поделиться этими деталями в вопросе. Во-вторых, что особенного в этом shell-скрипте, который нельзя запрограммировать на Java? Мне не кажется резонным, что у меня есть только Java-программное обеспечение только для Linux, которое вам нравится запускать с Cygwin. Либо укажите файл '.bat' (например, Tomcat), либо переместите функциональность в класс Java. И, наконец, я не считаю никого глупым. Но люди часто неопытные. – Bozho

4

Чтобы устранить разрыв между ответами aioobe и Bozho, я также посоветовал бы не устанавливать параметр line.separator при запуске JVM, так как это потенциально нарушает многие фундаментальные предположения, которые JVM и код библиотеки делают в среде, в которой выполняется. Например, если библиотека, на которую вы полагаетесь, полагается на line.separator, чтобы сохранить файл конфигурации кросс-платформенным способом, вы просто нарушили это поведение. Да, это кросс-кейс, но это делает его еще более гнусным, когда через несколько лет возникает проблема, и теперь весь ваш код зависит от этой настройки на месте, в то время как ваши библиотеки (правильно) принимают это нет.

Сказанное, иногда эти вещи не поддаются контролю, например, когда библиотека полагается на line.separator и не дает вам возможности явно переопределить это поведение. В таком случае вы застряли, переопределяя ценность, или что-то более болезненное, как повторное внедрение или исправление кода вручную.

Для тех ограниченных случаев, это приемлемо для переопределения line.separator, но мы должны следовать двум правилам:

  1. минимизировать объем переопределения
  2. не REVERT переопределения независимо от того, что

Оба эти требования хорошо обслуживаются AutoCloseable и синтаксисом try-with-resources, поэтому я внедрил класс PropertiesModifier, который обеспечивает чистоту обоих.

/** 
* 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); 
    } 
} 

Мой случай использования был с Files.write(), что является очень удобным способом, за исключением того, что явно полагается на line.separator. Обернув вызов Files.write(), я могу четко указать разделитель строк, который я хочу использовать, не рискуя подвергнуть его воздействию любых других частей моего приложения (обратите внимание, конечно, что это по-прежнему не является потокобезопасным).

try(PropertiesModifier pm = new PropertiesModifier("line.separator", "\n")) { 
    Files.write(file, ImmutableList.of(line), Charsets.UTF_8); 
} 
Смежные вопросы