#c #windows #qt #unicode #taglib
#c #Windows #qt #Юникод #taglib
Вопрос:
Проблема: Я хочу, чтобы TagLib::FileRef открыл файл с символами Юникода в имени файла или пути, но не удается.
Я скомпилировал TagLib 1.7 с помощью MinGW (GNU Make 3.81, GCC 4.4.0) под Windows 7 (64-разрядный, но 32-разрядный компилятор) после создания Makefile с помощью CMake 2.8.4. Я использую TagLib совместно с платформой Qt 4.7.2.
Для обмена строками между двумя библиотеками TagLib предоставляет:
#define QStringToTString(s) TagLib::String(s.toUtf8().data(), TagLib::String::UTF8)
#define TStringToQString(s) QString::fromUtf8(s.toCString(true))
// toUtf8() is a fix, originally spelled utf8(), but that's not relevant here.
Я сконструировал TagLib::FileRef следующим образом:
TagLib::FileRef fileRef( QStringToTString(filePath).toCString(true) );
// or:
TagLib::FileRef fileRef( TagLib::FileName( QStringToTString(filePath).toCString(true) ) );
В результате не удается загрузить файлы с путями, содержащими символы Unicode или символы Latin-1 с другим кодом в представлении UTF-8 (например, умляуты или китайские символы) (fileRef.isNull()).
Если я передам false функции toCString() выше (объявление: см. Ниже), TagLib может обрабатывать умляуты (но не символы только для Unicode). Поэтому я предполагаю, что я неправильно скомпилировал TagLib (TagLib::FileRef интерпретирует данную строку как Latin-1), но я не знаю, как проверить или даже исправить это. Примечание: Строки Unicode в тегах (ID3) правильно извлекаются с помощью TagLib.
toCString():
const char* TagLib::String::toCString( bool unicode = false ) const;
Документ: документация по TagLib
Ответ №1:
FileRef
Конструктор принимает FileName
объект (не String
!), который может быть char*
или wchar_t*
строкой. В Windows вы можете предположить, что оба wchar_t
и QChar
имеют 16 бит, поэтому вы можете просто передать их filePath.constData()
.
Обратите внимание, что если вы планируете запускать код на платформе, отличной от Windows, вам необходимо провести #ifdef
проверку при FileRef
создании объекта, потому что на других платформах он принимает только char*
строки, и вам следует использовать QFile::encodeName(filePath).constData()
.
Комментарии:
1. Спасибо,
TagLib::FileRef fileRef( reinterpret_cast<const wchar_t*>(filePath.constData()) );
хорошо работает под Windows. Я планирую запустить это на разных системах;QFile::encodeName()
вероятно, это будет кодироваться в UTF-8?2. Да, большинство других систем сейчас используют имена файлов в формате UTF-8, но обычно это зависит от настроек пользователя, поэтому вы не можете предположить, что это будет UTF-8.
Ответ №2:
Другой способ — использовать, toStdString()
за которым c_str()
следует.
QString path(...);
std::string stdString = path.toStdString();
const char *cPath = stdString.c_str();
TagLib::FileRef fr(cPath);
Обязательно сохраните stdString как переменную, так как без этого она будет уничтожена к концу строки.
По крайней мере, в моем случае оба QFile::encodeName(filePath)
и QString::toLocal8Bit()
завершились неудачей — они были заменены ąęóżłćĄĘŁ
на aeózlcAEL
(похоже, ó
мне повезло пережить это), что привело к сбою моего приложения. К сожалению, я не могу ответить, почему методы Qt не сработали в моем случае.