Как Найти Набор символов/Кодирование По умолчанию в Java?

Самое главное, где Вы отправите ошибки для своего средства отслеживания ошибки, прежде чем оно будет закончено?

, Но серьезно. Инструменты уже существуют, нет никакой потребности перестроить колесо. Изменение отслеживания инструментов для добавления определенных определенных опций является одной вещью (я изменил Trac прежде)... перезапись той просто глупа.

самая важная вещь, на которую можно указать, состоит в том, что, если все они хотят сделать, добавляют несколько специализированных отчетов, это не требует наземного решения. И кроме того, ПОСЛЕДНЕЕ место "Ваши доморощенные вопросы" решения для внутренних инструментов. Кто заботится о том, что Вы используете внутренне, если это делало задание, поскольку Вам нужен он?

88
задан Ciro Santilli 新疆改造中心法轮功六四事件 16 January 2015 в 12:29
поделиться

4 ответа

Это действительно странно ... После установки кодировка по умолчанию кэшируется и не изменяется, пока класс находится в памяти. Установка свойства «file.encoding» с помощью System.setProperty («file.encoding», «Latin-1»); ничего не делает. Каждый раз, когда вызывается Charset.defaultCharset () , он возвращает кешированную кодировку.

Вот мои результаты:

Default Charset=ISO-8859-1
file.encoding=Latin-1
Default Charset=ISO-8859-1
Default Charset in Use=ISO8859_1

Но я использую JVM 1.6.

(обновление)

Хорошо. Я воспроизвел вашу ошибку в JVM 1.5.

Если посмотреть на исходный код версии 1.5, кешированная кодировка по умолчанию не установлена. Я не знаю, ошибка это или нет, но 1.6 изменяет эту реализацию и использует кешированную кодировку:

JVM 1.5:

public static Charset defaultCharset() {
    synchronized (Charset.class) {
        if (defaultCharset == null) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                return cs;
            return forName("UTF-8");
        }
        return defaultCharset;
    }
}

JVM 1.6:

public static Charset defaultCharset() {
    if (defaultCharset == null) {
        synchronized (Charset.class) {
            java.security.PrivilegedAction pa =
                    new GetPropertyAction("file.encoding");
            String csn = (String) AccessController.doPrivileged(pa);
            Charset cs = lookup(csn);
            if (cs != null)
                defaultCharset = cs;
            else
                defaultCharset = forName("UTF-8");
        }
    }
    return defaultCharset;
}

Когда вы устанавливаете кодировку файла на file. encoding = Latin-1 в следующий раз, когда вы вызовете Charset.defaultCharset () , произойдет то, что, поскольку кэшированная кодировка по умолчанию не установлена, она попытается найти соответствующую кодировку для имени Latin-1 . Это имя не найдено, потому что оно неверно, и возвращает значение по умолчанию UTF-8 .

Что касается того, почему классы ввода-вывода, такие как OutputStreamWriter , возвращают неожиданный результат,
] реализация sun.nio.cs.StreamEncoder (которая используется этими классами ввода-вывода) также отличается для JVM 1.5 и JVM 1.6. Реализация JVM 1.6 основана на методе Charset.defaultCharset () для получения кодировки по умолчанию, если она не предоставляется классам ввода-вывода. Реализация JVM 1.5 использует другой метод Converters.getDefaultEncodingName (); для получения кодировки по умолчанию. Этот метод использует собственный кеш кодировки по умолчанию, которая устанавливается при инициализации JVM:

JVM 1.6:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Charset.defaultCharset().name();
    try {
        if (Charset.isSupported(csn))
            return new StreamEncoder(out, lock, Charset.forName(csn));
    } catch (IllegalCharsetNameException x) { }
    throw new UnsupportedEncodingException (csn);
}

JVM 1.5:

public static StreamEncoder forOutputStreamWriter(OutputStream out,
        Object lock,
        String charsetName)
        throws UnsupportedEncodingException
{
    String csn = charsetName;
    if (csn == null)
        csn = Converters.getDefaultEncodingName();
    if (!Converters.isCached(Converters.CHAR_TO_BYTE, csn)) {
        try {
            if (Charset.isSupported(csn))
                return new CharsetSE(out, lock, Charset.forName(csn));
        } catch (IllegalCharsetNameException x) { }
    }
    return new ConverterSE(out, lock, csn);
}

Но я согласен с комментариями. Вы не должны полагаться на это свойство . Это деталь реализации.

62
ответ дан 24 November 2019 в 07:37
поделиться

Это ошибка или особенность?

Похоже на неопределенное поведение. Я знаю, что на практике вы можете изменить кодировку по умолчанию, используя свойство командной строки, но я не думаю, что то, что происходит, когда вы это делаете, определено.

Идентификатор ошибки: 4153515 при проблемах с установкой этого свойства :

Это не ошибка. Свойство "file.encoding" не требуется для J2SE. спецификация платформы; это внутренняя деталь реализаций Sun и не должны проверяться или изменяться кодом пользователя. Это также должно быть только для чтения; технически невозможно поддерживать настройку этого свойства к произвольным значениям в командной строке или в любое другое время во время программы выполнение.

Предпочтительный способ изменить кодировку по умолчанию, используемую виртуальной машиной и средой выполнения. система должна изменить языковой стандарт базовой платформы перед запуском вашего Программа на Java.

Я съеживаюсь, когда вижу, что люди устанавливают кодировку в командной строке - вы не знаете, какой код это повлияет.

Если вы не хотите использовать кодировку по умолчанию, установите кодировку вы действительно хотите явно через соответствующий конструктор метода / .

24
ответ дан 24 November 2019 в 07:37
поделиться

Во-первых, Latin-1 совпадает с ISO-8859-1, поэтому значение по умолчанию уже было для вас приемлемым. Верно?

Вы успешно установили кодировку ISO-8859-1 с помощью параметра командной строки. Вы также программно устанавливаете его на «Latin-1», но это не распознанное значение кодировки файла для Java. См. http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html

Когда вы это сделаете, похоже, что Charset сбрасывается на UTF-8, если смотреть у источника. Это, по крайней мере, объясняет большую часть поведения.

Я не знаю, почему OutputStreamWriter показывает ISO8859_1. Он делегирует классы sun.misc. * С закрытым исходным кодом. Я предполагаю, что это не совсем касается кодирования с помощью того же механизма, что странно.

Но, конечно, вы всегда должны указывать, какую кодировку вы имеете в виду в этом коде. Я'

4
ответ дан 24 November 2019 в 07:37
поделиться

Поведение не так уж и странно. Если посмотреть на реализацию классов, то это вызвано:

  • Charset.defaultCharset () не кэширует определенный набор символов в Java 5.
  • Установка системного свойства "file.encoding" и вызов Charset.defaultCharset () снова вызывает вторую оценку системного свойства, набор символов с именем «Latin-1» не найден, поэтому для Charset.defaultCharset () по умолчанию используется «UTF -8 ".
  • OutputStreamWriter , однако, кэширует набор символов по умолчанию и, вероятно, уже используется во время инициализации виртуальной машины, поэтому его набор символов по умолчанию отличается от Charset.defaultCharset () если системное свойство file.encoding было изменено во время выполнения.

Как уже указывалось, не задокументировано, как виртуальная машина должна вести себя в такой ситуации. Документация API Charset.defaultCharset () не очень точна в отношении того, как определяется набор символов по умолчанию, только упоминается, что это обычно делается при запуске виртуальной машины на основе таких факторов, как набор символов ОС по умолчанию или языковой стандарт по умолчанию. .

4
ответ дан 24 November 2019 в 07:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: