Как определить кодировку id3-тега?

Имеется два mp3 файла для теста с тегами в Latin1, UTF-8 соответственно. Пытаюсь считать их:
System.out.println(id3v2Tag.getAlbum());

Вывод:
?????????? ????????: ???????? ?? ??? ???????
Эльфийская Рукопись: Сказание На Все Времена

Считываю так:
System.out.println(new String(id3v2Tag.getAlbum().getBytes("Latin1")));

Вывод:
Эльфийская Рукопись: Сказание На Все Времена
?????????? ????????: ???????? ?? ??? ???????

В эксплорере windows и плеерах оба тега выводятся нормально. Как они определяют кодировку?

И еще вопрос — почему вместо кракозяб выводятся знаки вопроса? Как jvm определяет что вывод некорректен и следует его заменить на знаки вопроса? Можно ли определить это в коде?

UPD: Действительно, первый файл был в cp1251, но тогда непонятно почему код:
System.out.println(new String(id3v2Tag.getAlbum().getBytes("Latin1")));

работает ок. Наверное, косяки в библиотеке, которую я юзаю для считывания тегов.
  • Вопрос задан
  • 6004 просмотра
Решения вопроса 1
@yupic
Поясню почему работает System.out.println(new String(id3v2Tag.getAlbum().getBytes(«Latin1»))).

Как я понимаю, вы используете некую библиотеку, которая умеет читать id3-теги.
Эта библиотека из файла читает сырой массив байт. Ей надо преобразовать байты в строку, для этого надо воспользоваться какой-то кодировкой. В идеале, эту кодировку надо бы задавать в настройках библиотеки. Но если кодировка не задана, то, видимо, используется Latin1.
Так вот, библиотека преобразует байты в строку с помощью Latin1. Происходит это так, берётся некий байт, ему ставится в соответствие некий символ и он сохраняется в строке. Например, считали байт, представляющий букву «А» в кодировке windows-1251, а в Latin1, этому байту будет сопоставлен какой-нибудь "Õ". Если вы преобразуете такую строку в массив байт, используя UTF-8 и запишете байты в файл, то при просмотре файла в UTF-8 вы не увидите русских букв.
Далее, вы хотите распечатать строку, для этого вы преобразуете её в байты используя Latin1. Символу "Õ" сопоставляется байт, который в windows-1251 представляет букву «А». Потом из этих байт опять создаётся строка, при этом используется системная кодировка по умолчанию — windows-1251. В результате, из байта получается символ «А», как и было задумано, и эта строка корректно выводится на экран.

Как поступить: в 1-м комменте дали ссылку на нужную вам библиотеку. Вам надо получать теги в виде массива байт, и преобразовывать их в строки, используя определённую juniversalchardet кодировку. Если библиотека для работы с MP3 не позволяет получить теги в виде массивов байт, то преобразовывать возвращаемые ей значения в байты используя Latin1, а лишь потом определять кодировку и создавать строки.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@S1ashka
Ответ написан
Комментировать
Что-то вы путаете. В кодировке latin1 нет кириллических символов. Скорее всего там cp1251.
Знаки вопроса выводятся вместо непечатных символов, которые могут иметь специальное значение и нарушить нормальную работу терминала. Безопаснее вывести знаки вопроса, тем более что смысла в бинарных крякозябрах вы много не увидите.

В эксплорере windows и плеерах оба тега выводятся нормально. Как они определяют кодировку?

С помощью магии. Анализируют ичпользуемые символы, частоты их появления, устойчивые комбинации символов. Самые продвинутые плееры просто считают, что теги в UTF-8, а все, кто хранят их в другой кодировке глубоко неправы. Лучше всего пользоваться как раз такими плеерами. Проблем меньше будет.
Ответ написан
vsespb
@vsespb
Наверное getBytes(«latin1») просто ничего не перекодирует, поэтому оно отображается в нативной windows кодировке.

Отличить ut8 от win1251 можно наверное без всякой магии. Русская буква в 1251 не будет являтся валидным utf8 символом. А вот отличить однобайтовые кодировки — нужен частотный анализ.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы