Настройка Java VM line.separator - PullRequest
14 голосов
/ 14 сентября 2010

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

java -Dline.separator="\n"

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

Ответы [ 3 ]

15 голосов
/ 14 сентября 2010

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

Вот тестовый прогон:

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

Примечание:

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

4 голосов
/ 14 мая 2014

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

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

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

  1. Свести к минимуму область переопределения
  2. Отменить отмену независимо от того, что

Оба эти требования хорошо выполняются синтаксисом 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);
}
3 голосов
/ 14 сентября 2010

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

...