Проблемы с потерей конфиг файла
November 3rd, 2009 Begemot Posted in Программирование
Хочу пожаловаться, может кто поможет советом. Есть программы на написанные на wxWidgets и MFC, стартуют вместе с виндой и завершаются с ней же. При старте, как и рекомендует хелп делаю
wxFileConfig * config = new wxFileConfig(wxGetApp().GetAppName(), wxGetApp().GetVendorName(), dataPath + wxT("clipdiary.cfg")); // will be deleted by wxWidgets automatically
wxConfigBase::Set(config);
Потом периодически читаю\пишу, иногда, но не всегда делаю Flush(true). При выходе из программы и\или при получении сообщения EVT_QUERY_END_SESSION пишу кое-какие данные в цфг, делаю Flush(true). В самом конце делаю делаю вот такое
int MyApp::OnExit()
{
// Баг, столкнулся с тем что почему-то не пишет в файл надо или flush или удалять указатель (при удалении он сам все пишет)
// по идее библиотека должна сама удалять объек. но не удаляет. так что будем вручную.
delete wxConfigBase::Set(NULL); // Flush and delete configreturn wxApp::OnExit();
}
А проблема в том, что периодически (редко) при запуске программы – конфиг файл оказывается пустой, в смысле или совсем пустой или отсутствующий, не могу точно сказать. Программа при загрузке выдает сообщение ошибку wxWidgets, что-то типа “ошибка конвертации в юникод” точно не помню. Скорее всего проблема происходит при выключении компьютера, наверняка при каком-то “плохом” завершении работы. Раньше об этом писали пользователи, жаловались на то что пропадают настройки… Недавно поймал такое у себя – висели три мои программы на mfc, wxWidgets trunk и 2.8.10 – две последние потеряли все настройки, мфц’шная нет. Вот думаю куда копать и что делать, уже думал делать дублирование настроек во втором файле, но какой-то это странный путь 🙂 Может кто знает как сделать правильно?
Кстати, вот инструкция как реализовать ручную загрузку функций из DLL или как в программе использовать функции из Vista API?
November 3rd, 2009 at 11:56 am
Я в подобном случае собрал работу с конфиг-файлом в отдельный объект. В методах, которым нужно прочитать или записать конфиг, инициализируется такой (локальный) объект. Чтение конфига у него в конструкторе, запись – в отдельном методе.
“Плохое” завершение работы конфиг не трогает вообще.
November 4th, 2009 at 4:20 pm
У меня работа с конфиг файлом происходит посредством собственных функций чтения/записи параметров. Причем, файл открывается – читается (пишется) параметр – закрывается. Проблем с потерей конфига не было даже при выключении питания.
int LoadUserParam( const wxString &Param, int Default )
{
wxFileConfig *config = new wxFileConfig( wxEmptyString, wxEmptyString, GetUserConfigFile(), wxEmptyString, wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
wxFileConfig::Set( config );
return config->Read( Param, Default );
}
bool SaveUserParam( const wxString &Param, int Value )
{
wxFileConfig *config = new wxFileConfig( wxEmptyString, wxEmptyString, GetUserConfigFile(), wxEmptyString, wxCONFIG_USE_NO_ESCAPE_CHARACTERS );
wxFileConfig::Set( config );
config->Write( Param, Value );
config->Flush();
return true;
}
Кстати, а почему wxConfigBase::Set(config)?
November 4th, 2009 at 8:48 pm
Ну вы жесткие пацаны, на каждый чих открывать\закрывать конфиг, я до такого не додумался 🙂 Неужели переписывать все…
А чо нет? что должно быть?
November 4th, 2009 at 10:42 pm
Зато надёжно 🙂 Хотя я собирался переделать его для блочного доступа, но теперь будем смотреть что у тебя получится.
Для wxFileConfig * config более красивым выглядит
wxFileConfig::Set( config ), но это только с эстетической точки зрения, поэтому я и поинтересовался, с какой целью вызывается wxConfigBase::Set(config)?
November 5th, 2009 at 10:30 am
Есть еще вариант вынести в отдельный конфиг-файл настройки программы (те, которые пользователь задает в диалоге Options).
Читаться они могут беспрепятственно, а запись жестко локализуется ОК’ем диалога Options. Подозреваю, что пользователей волнует слет именно этих настроек.
А остальную шелуху (запоминание последней позиции окна etc) оставить, как есть – слетит, так и черт с ней…
November 5th, 2009 at 11:23 am
Да настройки не только в диалоге программы, есть же еще галочки в меню, да и состояния окон, элементов тоже…
Уж тогда лучше действительно копировать файл, делая резервную копию 🙂
Буду в ближайшем будущем разбираться.
November 5th, 2009 at 1:25 pm
Однако, интересно знать, куда деваются настройки?
Теоретически, при любом сбое файл настроек должен ведь сохраниться. Я вижу пока только одну возможность – в момент flush когда он уже пометил старый файл пустым и не успел записать данные.
November 5th, 2009 at 3:12 pm
Резервное копирование либо не запомнит последних изменений (если будет делаться при запуске программы), либо еще затормозит сохранение настроек (если будет делаться перед ним).
Все-таки проблема, видимо, проявляется, когда запись настроек вызывается деструктором объекта. И решение, имхо, вытащить запись из деструктора. Если изменения настроек производятся действиями пользователя, то и сохранение изменений можно производить в обработчиках действий.
А то, может… у реестра вроде бы запись должна быть атомарной? 😉
November 5th, 2009 at 3:23 pm
Еще пару замечаний:
1. Исходники wxWidgets можно не теребить – аналогичная фигня у меня была под MFC и с использованием ofstream. Были и более странные глюки – типа файла нужного размера, заполненного 0x00.
2. Вариант Сергея, подозреваю, на самом деле вовсе не дергает зря винт – его микрозапросы прекрасно кэшируются, и чтение может быть произведено всего один раз, а запись быстренько встает в очередь и не убивается вместе с программой. Может, это как раз оптимум. Или я идеализирую нынешние системы?
November 8th, 2009 at 2:22 pm
нет, думаю что проблема при записи в момент выключения компьютера, после получения сигнала об этом…
November 9th, 2009 at 10:46 am
Я, собственно, это и имел в виду – что после получения сигнала о выключении программа бросается записывать свой конфиг. Если при этом была загружена, например, Опера с настройкой “очищать кэш при выходе”, то до винта не достучаться. Вопрос локализуется: нужно ли программе записывать свои настройки при выходе или эту запись можно перенести на другие события, пока машина не в аврале?
November 9th, 2009 at 2:29 pm
К сожалению у меня тут лично-рабочий аврал, поэтому я пока не занимаюсь этим:( может через неделю смогу.
Тогда потестю разные варианты, пока есть мысль может просто то что _нужно_ сохранять при выключении, перенести в другой конфиг 🙂
November 24th, 2009 at 9:52 pm
В виртуалке поставил обе программы, в автозагрузку добавил команду перезагрузки системы через две минуты. И так оно крутилось часов 6. Ничего не потерялось 🙁