Хранение настроек программы без INI-файлов и реестра.

При хранении настроек программы в INI-файле или реестре довольно трудоемким является считывание этих данных и инициализация внутренних структур/классов, хранящих настройки. Не лучше ли хранить сами эти классы, а еще лучше - форму, которая содержит интерфейс управления настройками программы.

Традиционный подход хранения настроек программы вынуждает программиста к написанию специального кода для записи/считывания данных в/из реестра или INI-файла.
При этом в программе реализуются условно три функции:
  1. Загрузка данных в специальную структуру (запись или класс) или в элементы формы настроек;
  2. Инициализация элементов в окне(форме) настроек;
  3. Сохранение данных;
При этом для каждой переменной необходимо прописывать, к примеру, ini.WriteInteger(...) и ini.ReadInteger(...). Т.е. при добавлении нового пункта в настройки необходимо прописывать соответствующий код в функции сохранени и чтения данных. Не очень-то удобно.
Можно, конечно, сохранять в файл класс, содержащий настройки. Но лучше пойти немного дальше и хранить в файле всю форму с настройками.
Для этого в файл проекта добавим код, загружающий нужную нам форму и ее сохраняющий.
Предположим, что файл настроек буден хранится в директормии программы и называться 'settings.dat', а форма - fSettings.

program _test; 
uses 
  Forms, 
  main in 'main.pas' {fMain}, 
  Settings in 'Settings.pas' {fSettings}; 
 
begin 
  Application.Initialize; 
  Application.CreateForm(TfMain, fMain); 
  ... 
 
  DeleteComponents(fSettings); 
  LoadComponentFromTextFile(fSettings, BinPath + 'settings.dat'); 
 
  Application.Run; 
   
  //...после завершения работы программы - сохраняем форму в файл. 
  SaveComponentToTextFile(fSettings, BinPath + 'settings.dat'); 
 
end. 


Но что произойдет, если мы в исходном проекте модифицируем сохраняемую форму? При чтении ресурса из файла мы потеряем все изменения. Условием проверки неизменности формы примем число контролов на форме. Также добавим код проверки существования файла и обработку исключений.

program _test; 
uses 
  Forms, 
  main in 'main.pas' {fMain}, 
  Settings in 'Settings.pas' {fSettings}; 
 
var 
  fTempSettings: TfSettings; 
begin 
  Application.Initialize; 
  Application.CreateForm(TfMain, fMain); 
  ... 
 
 
 
  //...если файл существует, то... 
  if FileExists(BinPath + 'settings.dat') then 
  begin 
    //...создаем временную форму 
    fTempSettings := TfSettings.Create(nil); 
    //...очищаем 
    DeleteComponents(fTempSettings); 
    try 
      //...загружаем 
      LoadComponentFromTextFile(fTempSettings, BinPath + 'settings.dat'); 
      //...если форма не изменилась, то загружаем рабочую форму 
      if fTempSettings.ComponentCount = fSettings.ComponentCount then
      //..form unchanged - can load resource 
      begin 
        DeleteComponents(fSettings); 
        LoadComponentFromTextFile(fSettings, BinPath + 'settings.dat'); 
      end; 
    except 
      FreeAndNil(fTempSettings); 
    end; 
  end; 
 
  Application.Run; 
   
  //...после завершения работы программы - сохраняем форму в файл. 
  SaveComponentToTextFile(fSettings, BinPath + 'settings.dat'); 
 
end. 

Необходимо привести еще код функций, которые мы использовали для очистки формы, а также сохранения/чтения компонента.

//...процедура удаляет все дочерние компоненты из формы 
procedure DeleteComponents(Form: TForm); 
begin 
  while Form.ComponentCount > 0 do Form.Components[0].Free; 
end; 
 
//...процедура загружает(инициализирует) компонент из текстового файла с ресурсом 
procedure LoadComponentFromTextFile(Component: TComponent; const FileName: string); 
var 
  ms: TMemoryStream; 
  fs: TFileStream; 
begin 
  ms := TMemoryStream.Create; 
  fs := TFileStream.Create(FileName, fmOpenRead); 
  try 
    ObjectTextToBinary(fs, ms); 
    ms.position := 0; 
    ms.ReadComponent(Component); 
  finally 
    ms.Free; 
    fs.free; 
  end; 
end; 
 
//...процедура сохраняет компонент в текстовый файл 
procedure SaveComponentToTextFile(Component: TComponent; const FileName: string); 
var 
  ms: TMemoryStream; 
  fs: TFileStream; 
begin 
  fs := TFileStream.Create(FileName, fmCreate or fmOpenWrite); 
  ms := TMemoryStream.Create; 
  try 
    ms.WriteComponent(Component); 
    ms.position := 0; 
    ObjectBinaryToText(ms, fs); 
  finally 
    ms.Free; 
    fs.free; 
  end; 
end; 


Ресурс формы можно хранить не в текстовом, но и в двоичном виде. Это компактнее, операции чтения и записи выполняются быстрее, но отнимет возможность внести изменения в файл настроек вручную. При веденный метод, по нашему мнению, позволяет упростить организацию работы с настройками в программе. Чего и всем желаем.

составление статьи: Андрей Чудин, ЦПР ТД Библио-Глобус.