Russian Qt Forum
Апрель 28, 2024, 01:04 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Сериализация QString содержащей структуры.  (Прочитано 7873 раз)
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« : Май 17, 2013, 06:09 »

Всем снова привет!
Есть структура, которую я записываю в бинарный файл с помощью QDataStream::writeRawData.
Отдельно выписываю каждый QString через оператор <<.
При чтении этого файла, чтение структуры проходит успешно. А вот при чтении в QString выдает ошибку (realloc или чё-то там...)
Вскоре понял, что это происходит из-за того значения, которое передаётся в QString при чтении файла. Решил проблему с помощью QString::clear() и последующим чтением QString из файла. Только теперь уже проблема возникла иная: при закрытии программы выскакивает что-то вроде  heap corruped.
Вопрос: какое именно значение из QString записывается при сериализации и как при десериализации избежать переписывания QString переменных или "сохранить нынешние значения QString (которое затирается при деериализации) -> прочитать файл -> восстановить это значение)
Спасибо
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #1 : Май 17, 2013, 11:56 »

Трижды перечитал вопрос - так и не понял про что он. Давай, что-ли с публикации проблемного кода начнем?
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #2 : Май 18, 2013, 11:27 »

Сама структура:
Код:
#ifndef SOLUTIONSETTINGS_H
#define SOLUTIONSETTINGS_H

class QString;

struct ComponentSettings
{
QString name;
double concentration;
double liquidusTangent;
double distributionRatio;
};

struct SolutionSettings
{
int substrateHeight;
int addingLayerHeight;
int addingLayerCount;
double areaWidth;
double areaDepth;
int NodesPerSize;
int laserSpotDiameter;
int laserPower;
int preheatingTemperature;
int gasTemperature;
int laserSpeed;
int distanceBetweenPasses;
int penetrationRatio;
int delayAfterHeating;
QString wayType;
double delayBetweenPasses;
double calculationTimeStep;
int outputTimeStep;
QString materialName;
double liquidusTemperature;
double coresCount;
double growSpeedRatio;
double interaxialDistance;
double porosity;
double particlesDiameter;
ComponentSettings component1,
  component2,
  component3;
};

#endif

Её записываем в файл.
Код:
	out.writeRawData(reinterpret_cast<char*>(&_settings), sizeof(_settings));

out << _settings.wayType
<< _settings.materialName
<< _settings.component1.name
<< _settings.component2.name
<< _settings.component3.name;
binFile.close();
где
Код:
	SolutionSettings _settings;
и
Код:
	QFile binFile(slmFilePath);
binFile.open(QIODevice::WriteOnly);
QDataStream out(&binFile);
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #3 : Май 18, 2013, 11:42 »

При чтении уже в другой программе:
Код:
	in.readRawData(reinterpret_cast<char*>(&settings), sizeof(settings));
где
Код:
	QFile file(filePath);
file.open(QIODevice::ReadOnly);
QDataStream in(&file);

для чтения строк изначально написал
Код:
	in >> settings.wayType;
in >> settings.materialName;
in >> settings.component1.name;
in >> settings.component2.name;
in >> settings.component3.name;
но, этот код выдавал ошибку при выполнении первой функции. Была какая-то проблема с распределением памяти. Но её я обошёл тем, что для каждой из читаемой строки выполнил метод QString::clear(). Всё пошло гладко, но только по завершению работы приложения выдается ошибка heap corruption detected...

То есть, я полагаю, что при чтении из файла целиком структуры, в элементы QString были записаны какие-то произвольные значения (которые были рабочими при записи в файл). Таким образом, эти значения дают понять, что при выполнении некого деструктора (который выполняется по завершению программы) производится очистка памяти по тем самым значениям, которые были вписаны в структуру из файла, но они являются не актуальными, так как не относятся к выполняемому процессу, а просто были считаны из файла.
Записан
thechicho
Гость
« Ответ #4 : Май 18, 2013, 11:48 »

а чо QSettings не воспользуетесь?
Записан
mutineer
Гость
« Ответ #5 : Май 18, 2013, 11:52 »

Писать QString в виде бинарного потока в одном процессе и вычитывать в другом это очень опасно, он наверняка имеет какие-то внутренние указатели, которые в другой программе невалидны. Не делай так, записывай всю структуру через QDataStream и операторы записи в поток
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #6 : Май 18, 2013, 12:36 »

а чо QSettings не воспользуетесь?
Так как это не единственное, что я записываю в файл. Туда ещё идёт свыше 1000 QVector

Писать QString в виде бинарного потока в одном процессе и вычитывать в другом это очень опасно, он наверняка имеет какие-то внутренние указатели, которые в другой программе невалидны. Не делай так, записывай всю структуру через QDataStream и операторы записи в поток
вот я про эти указатели и говорю. Как-то мучительно получается по отдельности записывать и считывать каждый элемент в отдельности + при добавлении элементов в структуру нужно искать чтение и запись и снова добавлять... Уверен, что должен быть какой-то другой способ. У меня появились некоторые идеи, сейчас попробую их спрораммировать, позже отпишусь по результатам, может кому полезно будет
Записан
mutineer
Гость
« Ответ #7 : Май 18, 2013, 12:40 »

Перегрузи операторы << и >> для своей структуры и тогда все будет выглядеть просто как
Код
C++ (Qt)
out << settings;
...
in >> settings;
 

и при изменении структуры поменять надо будет только эти два оператора
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #8 : Май 18, 2013, 14:52 »

Нашёл выход, более подходящий для меня!
Запись структуры оставить такой же, как я описывал выше. Но, конечно, как в моём случае вписываются лишние 5 * sizeof(QString) байт - думаю, для меня это не критично.

Перед чтением файла нужно сохранить значения в каждом из QString. А после чтения восстановить их на прежние места.
Иными словами:
Код:
	char* strings[] = 
{
reinterpret_cast<char*>(&settings.wayType),
reinterpret_cast<char*>(&settings.materialName),
reinterpret_cast<char*>(&settings.component1.name),
reinterpret_cast<char*>(&settings.component2.name),
reinterpret_cast<char*>(&settings.component3.name)
};
char oldValues[sizeof(strings) / sizeof(char*) * sizeof(QString)];
for (int i = 0; i < sizeof(strings) / sizeof(char*); i++)
{
char* string = strings[i];
for (int j = 0; j < sizeof(QString) / sizeof(char); j++)
{
oldValues[sizeof(QString) / sizeof(char) * i + j] = string[j];
}
}

in.readRawData(reinterpret_cast<char*>(&settings), sizeof(settings));

for (int i = 0; i < sizeof(strings) / sizeof(char*); i++)
{
char* string = strings[i];
for (int j = 0; j < sizeof(QString) / sizeof(char); j++)
{
string[j] = oldValues[sizeof(QString) / sizeof(char) * i + j];
}
}

in >> settings.wayType;
in >> settings.materialName;
in >> settings.component1.name;
in >> settings.component2.name;
in >> settings.component3.name;
в середине можно было использовать memcpy, но я его не особо люблю.
Теперь изменение структуры никак не повлияет на код чтения/записи. Если не трогать классы.
Спасибо всем за советы.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Май 18, 2013, 15:04 »

Впечатление "хоть говори - хоть стреляЙ"  Улыбающийся Просто-напросто НЕ используйте readRawData/writeRawData, они только для сишных структур (и то не всегда). Пишите/читайте QString операторами <<  >>  - это все что нужно.

[/offtop]Не, не дойдет  Плачущий
Записан
mutineer
Гость
« Ответ #10 : Май 18, 2013, 15:19 »

Ужас какой...
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #11 : Май 23, 2013, 09:19 »

да уж, код ужасен.
я всегда пишу C-строки в бинарные файлы для совместимости с другими прогами, которые написаны не на Qt/C++ (Delphi например).
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #12 : Май 30, 2013, 11:19 »

Да, согласен, что код ужасен.

А в этой же теме хочу спросить по поводу writeRawData.
Каким образом, не используя эту функцию можно записать данные (особенно double), чтобы они в последствии могли быть считаны в среде разработки delphi?
Записан
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #13 : Май 31, 2013, 12:36 »

Код
C++ (Qt)
double value = 123.456;
out << value;

Код
Delphi
Value: Double;
Stream.Read(@Value, SizeOf(Value));
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Май 31, 2013, 13:31 »

Дополняя предыдущий ответ: перед записью надо установить QDataStream::setByteOrder с аргументом чтобы понравился дельфи (вероятно QDataStream::LittleEndian)
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.111 секунд. Запросов: 23.