Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++ Builder
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 148, средняя оценка - 4.86
LK
Заблокирован
#1

INI - Загрузка и сохранение настроек - C++ Builder

10.01.2013, 05:40. Просмотров 24998. Ответов 0
Метки нет (Все метки)

Сохраняем настройки в INI-файлах

Большинство программистов сталкиваются с проблемой сохранения настроек своей программы, но сегодня мы решим эту проблему. Мы научимся работать с ini файлами. Еще одним способом сохранять настройки является реестр, но его лучше не изменять, да и работать с ним немного сложнее.

Итак, ini-файл имеет простую и понятную структуру :
[Секция1]
Идентификатор1 = Значение1
Идентификатор2 = Значение2
[Секция2]
Идентификатор1 = Значение1
Для использования ini-файлов, в C++Builder предусмотрен модуль IniFiles , его мы и подключаем:
C++
1
#include "IniFiles.hpp"
Далее, нужно создать обьект класса TIniFile, назовем его Ini.

После
C++
1
TForm1 *Form1;
пишем:
C++
1
TIniFile *Ini = new TIniFile("c:/options.ini");
значения сохраняет на диске С: в файл options.ini .

После этого, на форму кинем две кнопки (TButton) и два Эдита (TEdit). Мы будем сохранять текст Эдитов в ini-файл, а потом загружать его.
Пишем обработчик события нажатия кнопки Button1. Она будет сохранять текст Эдитов в наш options.ini
C++
1
2
3
4
5
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    Ini->WriteString("Edits","Edit1",Edit1->Text);
    Ini->WriteString("Edits","Edit2",Edit2->Text);
}
Так, как мы работаем с текстом, мы использовали метод класса WriteString,
если нам нужно было бы работать с числами, мы бы написали WriteInteger .

Где параметры для этой функции:
"Edits" - имя секции;
"Edit1" - указатель на объект;
"Edit1->Text" - строка, которую мы сохраняем (текст эдита).

Далее, рассмотрим пример загрузки параметров с ini , пишем обработчик события для второй кнопки:
C++
1
2
3
4
5
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    Edit1->Text = Ini->ReadString("Edits","Edit1","Def");
    Edit2->Text = Ini->ReadString("Edits","Edit2","Def");
}
Здесь используем функцию чтения :ReadString , где:

"Edits" - секция из которая нам надо ;
"Edit1" - объект для которого загружаем строку;
"Def" - эта строка заполняет Эдит, если значение ini не найдено;

Этот маленький пример показывает как можно лекго загружать и сохранять параметры программы в INI-файлы.

Методы и свойства реализуемые TIniFile
Использовать или установить это ... Чтобы сделать это ... Наследование
Код
Create			Сконструировать экземпляр TIniFile.				TObject
DeleteKey			Удалить идентификатор INI-файла и его значение.		Нет
EraseSection		Убрать из INI-файла целый раздел.				Нет
FileName			Получить инкапсулированное имя INI-файла.			Нет
ReadBool			Извлечь из INI-файла логическое значение.			Нет
Readinteger			Извлечь из INI-файла целое значение.			Нет
ReadSection			Извлечь из раздела INI-файла имена идентификаторов.	Нет
ReadSections		Извлечь из INI-файла список имен разделов.		Нет
ReadSectionValues		Извлечь из INI-файла все содержимое раздела.		Нет
ReadString			Извлечь из INI-файла строковое значение.			Нет
WriteBool			Записать в INI-файл логическое значение.			Нет
Writeinteger		Записать в INI-файл целое значение				Нет
WriteString			Записать в INI-файл строковое значение			Нет
Важно
Методы ТIniFile будут пытаться найти INI-файл в каталоге Windows. Если вы хотите читать или писать INI-файл, расположенный не в каталоге Windows, следует явно добавить путь к имени INI-файла при его открытии в Create.

Автозагрузка конфигурации

Создаем 2 кнопки, раздела меню, т.д которые будут отвечать за запись файла, чтение файла конфигурации.

Код примерно такой (для 2 CheckBox'ов):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// SAVE
void __fastcall TForm1::Button1Click(TObject *Sender){
  AnsiString FileName = ExtractFilePath( Application->ExeName ) + "config.dat";
  ofstream fout( FileName.c_str() );
 
  if( fout ){
    fout << CheckBox1->Checked << endl;
    fout << CheckBox2->Checked << endl;
    fout.close();
  }
}
// LOAD
void __fastcall TForm1::Button2Click(TObject *Sender){
  AnsiString FileName = ExtractFilePath( Application->ExeName ) + "config.dat";
  ifstream fin( FileName.c_str() );
  bool check = false;
 
  if( fin ){
    CheckBox1->Checked = ( fin >> check, check );
    CheckBox2->Checked = ( fin >> check, check );
    fin.close();
  }
}
Теперь для записи конфигурации нужно вызвать функцию
C++
1
Button1Click(Sender);
для чтения
C++
1
Button2Click( Sender );
Например чтобы при закрытии приложения конфигурация автомитически сохранялась, надо написать обработчик события OnClose для формы.
C++
1
2
3
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action){
  Button1Click( Sender );
}
Чтобы автоматически загружалась - обработчик OnCreate
C++
1
2
3
void __fastcall TForm1::FormCreate(TObject *Sender){
  Button2Click( Sender );
}
для работы ofstream и ifstream необходимо включить заголовочный файл
C++
1
#include <fstream.h>
Обработка события изменения CheckBox - OnClick
C++
1
2
3
4
5
6
7
void __fastcall TForm1::CheckBox1Click(TObject *Sender){
  if( CheckBox1->Checked ){
//...
  } else{
//...
  }
}
Сделать структуру, например, в .h-файле, такого вида:
C++
1
2
3
4
struct TParameters
{
  bool IfFormatCOnUpload;  // всякие параметры, например, - булевские переменные
};
Создать объект этой структуры.

Например, в FormDestroy все писать в реестр, в Ini-файл или в какой-нибудь бинарный, а при создании окна все загружать и проставлять индикаторы.

При изменении параметры структуры тоже изменять или же смотреть все в самом конце.

Чтобы узнать последнюю просматривавшуюся, надо в OnChange у комбобокса написать:
C++
1
LastIndex = ComboBox1->ItemIndex;
Ini-объект можно просто оздать в начале, удалил в конце.

Код с комментариями.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
TIniFile * Ini; // объект .ini-файла
 
void __fastcall TForm1::WriteParams()  // запись всех значений в .ini-файл
{
   Ini->WriteInteger ( "Form1", "Form1Width",         Width               );  // ширина
   Ini->WriteInteger ( "Form1", "Form1Height",        Height              );  // высота
   Ini->WriteInteger ( "Form1", "Form1Top",           Top                 );  // вершина
   Ini->WriteInteger ( "Form1", "Form1Left",          Left                );  // лево
   Ini->WriteString  ( "Form1", "Form1Caption",       Caption             );  // заголовок
   Ini->WriteInteger ( "Form1", "ComboBox1ItemIndex", ComboBox1->ItemIndex);  // индекс
   Ini->WriteBool    ( "Form1", "CheckBox1Checked",   CheckBox1->Checked  );  // состояние 1
   Ini->WriteBool    ( "Form1", "CheckBox2Checked",   CheckBox2->Checked  );  // состояние 2
   Ini->WriteBool    ( "Form1", "InitMax",    WindowState == wsMaximized  );  // вид формы
   Ini->WriteString  ( "Memos", "Form1Memo1",         Memo1->Text         );  // содержимое
   Ini->UpdateFile();  // это обязательно, чтобы заново переписался файл
}
 
void __fastcall TForm1::ReadParams()
{
   Width                = Ini->ReadInteger( "Form1", "Form1Width",         800     );  // ширина
   Height               = Ini->ReadInteger( "Form1", "Form1Height",        600     );  // высота
   Top                  = Ini->ReadInteger( "Form1", "Form1Top",           100     );  // вершина
   Left                 = Ini->ReadInteger( "Form1", "Form1Left",          200     );  // лево
   Caption              = Ini->ReadString ( "Form1", "Form1Caption",       "MyProg");  // заголовок
   ComboBox1->ItemIndex = Ini->ReadInteger( "Form1", "ComboBox1ItemIndex", 0       );  // индекс
   CheckBox1->Checked   = Ini->ReadBool   ( "Form1", "CheckBox1Checked",   true    );  // состояние 1
   CheckBox2->Checked   = Ini->ReadBool   ( "Form1", "CheckBox2Checked",   true    );  // состояние 2
   WindowState          = Ini->ReadBool   ( "Form1", "InitMax", false) ? wsMaximized : wsNormal;
   Memo1->Text          = Ini->ReadString ( "Memos", "Form1Memo1",         ""      );  // содержимое
}
 
void __fastcall TForm1::FormCreate(TObject * Sender)  // создание формы
{
  Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "mytestini.ini");  // создаем объект
  ReadParams();   // считываем все в поля из файла
}
 
void __fastcall TForm1::FormDestroy(TObject * Sender)
{
  WriteParams();  // записываем все в последний раз
  delete Ini;     // удаляем объект
}
 
void __fastcall TForm1::BtnSaveClick(TObject * Sender)
{  WriteParams();  }  // сохранение при нажатии кнопки
 
void __fastcall TForm1::BtnLoadClick(TObject * Sender)
{  ReadParams();  }   // загрузка при нажатии кнопки
Чтобы не приучатся писать лишнего кода достаточно объявить функции
C++
1
2
void __fastcall ReadParams( TObject *Sender );
void __fastcall WriteParams( TObject *Sender );
в части класса формы
C++
1
(TForm1) __published:
и потом в инсперторе объектов для BtnLoad обработчиком события выбрать ReadParams.

Для Save аналогично.

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

Запись данных из файла INI в Memo
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TIniFile *ini = new TIniFile(ExtractFileDir(Application->ExeName) + "\\MyFile.ini");
  TStringList* Sections = new TStringList;
  TStringList* Values = new TStringList;
  if (ini) {
    ini->ReadSections(Sections);
    for (int i=0; i<Sections->Count; i++) {
      Memo1->Lines->Add("--------------\r\n" + Sections->Strings[i] + "\r\n--------------");
      ini->ReadSectionValues(Sections->Strings[i], Values);
      for (int j=0; j<Values->Count; j++) Memo1->Lines->Add(Values->Strings[j]);
    }
    delete ini;
  }
 
  delete Values;
  delete Sections;
}
Как создать Ini-файл в директории программы

По умолчанию ini-файл создается в Windows-директории (например: TIniFile.Create('FOO.INI' )), что приводит к "захламлению" оной. Более (эко-)логично (за исключением случаев, когда программа делается для CD-ROM) если ini-файл создается в той же директории что и главная программа. Это достигается с помощью одной строки:
C++
1
IniFile := TIniFile.Create(ChangeFileExt(ParamStr(0),'.INI'));
Как сохранить FontDlg->Style в ini-файле
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
TFont *CaptionFont = new TFont();
//Параметры стиля запоминается как bool значения
//Установку параметра шрифта проверяем через Contains
//Запись параметров шрифта
ini->WriteString(Key, "CFN", CaptionFont->Name);//
ini->WriteInteger(Key, "CFS", CaptionFont->Size);//
ini->WriteInteger(Key, "CFC", (int)CaptionFont->Color);//
ini->WriteInteger(Key, "CFE", (int)CaptionFont->Charset);//
ini->WriteBool(Key, "CFB", CaptionFont->Style.Contains(fsBold));
ini->WriteBool(Key, "CFI", CaptionFont->Style.Contains(fsItalic));//
ini->WriteBool(Key, "CFU", CaptionFont->Style.Contains(fsUnderline));//
ini->WriteBool(Key, "CFO", CaptionFont->Style.Contains(fsStrikeOut));//
 
//Чтение параметров шрифта
//ПРи чтении внвчале сбрасываем все параметры шрифта, а потом добавляем
//требуемый в множество в соответствии с прочитанным bool параметром
//Может можно и удалять эелементы из множества,
//но что-то в Help'е описывают только добавление.
CaptionFont->Style.Clear();//Сбросить параметры шрифта
CaptionFont->Name = ini->ReadString(Key, "CFN", CaptionFont->Name);//
CaptionFont->Size = ini->ReadInteger(Key, "CFS", 12);//
CaptionFont->Color = (TColor) ini->ReadInteger(Key, "CFC", clBlack);//
CaptionFont->Charset = (unsigned char)ini->ReadInteger(Key, "CFE", 204);//
if (ini->ReadBool(Key, "CFB", false))//
CaptionFont->Style = CaptionFont->Style << fsBold;//
if (ini->ReadBool(Key, "CFI", false))//
CaptionFont->Style = CaptionFont->Style << fsItalic;//
if (ini->ReadBool(Key, "CFU", false))//
CaptionFont->Style = CaptionFont->Style << fsUnderline;//
if (ini->ReadBool(Key, "CFO", false))//
CaptionFont->Style = CaptionFont->Style << fsStrikeOut;//
 
//P.S.: по идее должно работать и просто CaptionFont->Style << fsItalic;
//вместо CaptionFont->Style = CaptionFont->Style << fsItalic;
Как записать и считать переменную из ini
C++
1
2
3
4
5
6
7
8
9
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  AnsiString info = "ABCDEFGH";
  TIniFile *ini = new TIniFile("C:\\Program Files\\Borland\\CBuilder6\\Projects\\pr_ini\\file.ini");
  ini->WriteString( "section", "name", info);
  AnsiString info2 = ini->ReadString( "section", "name", "No Value");
  ShowMessage(info2); // получаем ABCDEFGH
  delete ini; ini = NULL;
}
Как считать секцию из файла ini
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <Inifiles.hpp>
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  TIniFile* pif = new TIniFile("WIN.INI");
  pif->ReadSections(ListBox1->Items);
  pif->ReadSection("Ports",ListBox2->Items);
  pif->ReadSectionValues("Ports",ListBox3->Items);
  delete pif;
}
 
MyIni->WriteInteger("NumOfItems","ItemsCount",ListBox1->Items->Count);
for (int j=0,cnt=ListBox1->Items->Count;j<cnt;j++) {
  MyIni->WriteString("Listbox","Item"+IntToStr(j),ListBox1->Items->Strings[j]);
}
 
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 int j,cnt;
 cnt=StrToInt(MyIni->ReadString("NumOfItems","ItemsCount","0"));
 for (j=0;j<cnt;j++)
 ListBox1->Items->Add(MyIni->ReadString("ListBox","Item"+IntToStr(j),"N/A"));
}
Количество секций и ключей
C++
1
2
3
4
5
6
7
8
9
TIniFile *iniFile = TIniFile(iniFileName);
TStringList *iniKeys = new TStringList;
TStringList *iniSections = new TStringList;
 
iniFile->ReadSections(iniSections);
ShowMessage(IntToStr(iniSections->Count)); // Количество секций
 
iniFile->ReadSection("General", iniKeys);
ShowMessage(IntToStr(iniKeys->Count)); // Количество ключей
Количество ключей в секции
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
TIniFile *iniFile = TIniFile(iniFileName);
TStringList *iniKeys = new TStringList;
TStringList *iniSections = new TStringList;
iniFile->ReadSections(iniSections);
ShowMessage(IntToStr(iniSections->Count)); // Количество секций
iniFile->ReadSection(SectionName, iniKeys);
ShowMessage(IntToStr(iniKeys->Count)); // Количество ключей
  unsigned long int CIni::ulSectionSize(const char *pszSection) {
  unsigned long int ulRes = 0;
  const unsigned int uiBuffLen = LINES_PER_SECTION * LINE_LEN;
  char szBuff[uiBuffLen];
  memset(szBuff, 0, uiBuffLen);
 
  GetPrivateProfileSection(pszSection, szBuff, uiBuffLen, m_sFilePath.c_str());
  //"Key1=xxx1"0"Key2=xxx2"0"Key2=xxx2"
  //если секция пустая
  if (szBuff[0] == '\0') {
    return 0;
  } 
  //секция не пустая
  for (int i = 0; i < uiBuffLen; i ++) {
    if (szBuff[i] == '\0') {
      ulRes ++;
       //конец данных '\0\0'
       if (szBuff[i + 1] == '\0') {
         break;
      }                
    }
  }    
  return ulRes;
}
Дополнительно

Файл конфигурации
Working with INI Configuration Files Cross-Platform (Win32/Un*x, MBCS/Unicode)

IniFilesTMemIniFile (C++)
Using TIniFile and TMemIniFile
Using TRegistryIniFile
THashedStringList

http://www.cyberforum.ru/cpp-builder/thread92542.html
http://www.cyberforum.ru/cpp-builder/thread366167.html
http://www.cyberforum.ru/cpp-builder/thread366104.html
http://www.cyberforum.ru/cpp-builder/thread617116.html
http://www.cyberforum.ru/cpp-builder/thread53782.html
http://www.cyberforum.ru/cpp-builder/thread366104.html
http://www.cyberforum.ru/cpp-builder/thread608085.html

StringList - Связь с INI-файлами
Парсер файлов ini
Работа с файлами INI
SimpleIni
How to use an ini file in C++Builder

Исходники
Запись и считывание очень длинной строки
Проект с примером реализации: Калькулятор Buidler

Не по теме:

Всех источников не помню. По поводу авторских прав, ошибок, дополнений и улучшений - пишите в личку.


http://www.cyberforum.ru/cpp-builder/thread1118364.html
23
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.01.2013, 05:40
Я подобрал для вас темы с готовыми решениями и ответами на вопрос INI - Загрузка и сохранение настроек (C++ Builder):

Сохранение настроек в Ini из ComboBox.
Разобрался с ini файлом, вот только возник вопрос, как сохранить настройки из...

Сохранение настроек программы в *ini файл.
Как сохранить параметры программы в файл *ini ?

Загрузка настроек из INI файла для CheckBox
Сохранение и загрузка настроек из INI файла. Настройки все удачно сохраняются,...

Загрузка настроек из ini файла, что-то странное...
Всем привет! Написал я тут одну прогу. Она сохраняет свои настройки в...

Сохранение TrackBar->Position в ini, ошибка (unable to write to options.ini)
TIniFile *Ini = new TIniFile(&quot;options.ini&quot;); void __fastcall...

0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.01.2013, 05:40
Привет! Вот еще темы с решениями:

Сохранение положения компонента на форме (Сохранение параметра в Ini-файл)
Не знаю верно ли назвал тему. Доброго вечера тебе, всяк сюда входящий....

Определение локализации Windows + считывание настроек из INI
Всем привет. :) Есть два вопроса. 1. Как определить локализацию Windows ?...

Сохранение настроек.
Есть много чекбоксов. Как можно сохранить у файл или инифайл то, отмечен ли...

Сохранение настроек
Доброго времени суток. Как можно сохранять настройки порограмы.Зарание спасибо.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru