Проблема с кодировкой в QT
Извиняюсь за тавтологию, допущенную ниже, это с целью максимальной понятности. Суть моей программы сводится к тому что она запоминает изменения, произведенные в текстовом файле, сохраняя измененный текст во временный файл temp, а его имя и адрес в файл fn, не изменяя при этом исходный файл пока пользователь не нажмет соответствующую кнопку или сочетание клавиш. Скомпилировал программу в Windows 10 и обнаружил, что после закрытия и повторного запуска она некорректно читает содержимое файла fn. Причем, записывается он вполне нормально, то есть, в самом файле fn никаких крокозябр нет. Да и функция открытия файла с ручным выбором файла тоже работает как надо. Я так понимаю, авария происходит где-то на этом этапе: FN=str; FN - это глобальная переменная QString. Код, реализующий функцию считывания имени файла и адреса, представлен ниже. Подскажите, пожалуйста, где и как тут прописать виндозовскую кодировку.
Qt Creator 4.14.0 Основан на Qt 5.15.2 (MSVC 2019, 64 бита)
//значит, о том, что тут происходит, по порядку. Тут мы вызываем метод QFile по имени name, который читает содержимое файла "fn"
QFile name("fn");
if (!name.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QString str; //объявляем текстовую переменную для хранения пути и имени файла, которые мы собираемся получить в следующей строке
str = name.readAll(); //переменная str получает полное содержимое файла fn из переменной name
FN=str; // Глобальная переменная FN теперь содержит тоже, что и переменная str
statusBar()->showMessage("Открыт файл " + FN); //Выводим сообщение в статус-бар
Ответы (3 шт):
str = name.readAll(); //переменная str получает полное содержимое файла fn из переменной name
В этой строчке readAll() возвращает QByteArray с содержимым файла, из которого уже конструируется QString. Так вот operator=() присваивая QString из QByteArray преобразует текст в нём в строку из кодировки utf8 (для Qt5) аналогично вызову QString::fromUtf8().
В зависимости от конкретной необходимости можно сделать:
Сохранить файл
fnв utf-8 и, желательно, явно использоватьQString::fromUtf8().Сохранить его в локальной кодировке для данной машины и использовать
QString::fromLocal8bit(). На win с русским языком это обычноcp1251.Сохранить его в любой заранее выбранной кодировке и открывать его явно в нужной с помощью
QTextCodecкак-то так:QTextCodec *codec = QTextCodec::codecForName("ibm866"); assert(codec); str = codec->toUnicode(name.readAll());
К делу не относится, но дабы избегать подобных ошибок, хорошей практикой является отключение конструкторов QString из QByteArray/char* с помощью объявления QT_NO_CAST_FROM_ASCII; и при создании QString всегда явно использовать функции вида fromLocal8Bit/Utf8/Latin1 и т.п.
В итоге справился с задачей, ниже код решения:
QFile name("fn");
if (!name.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QString str;
QTextCodec *codec = QTextCodec::codecForName("CP1251"); //Вот оно, тут
assert(codec); // И тут
str = codec->toUnicode(name.readAll()); // И здесь
FN=str; // Глобальная переменная FN теперь содержит тоже, что и переменная str
statusBar()->showMessage("Открыт файл " + FN);
Вообще, программа изначально задумана под Linux и вроде бы неплохо там работает без свистоплясок с кодировками, поэтому для данного примера я решил уточнить условия компиляции в зависимости от операционной системы.

