Obsługa Plików Ini.
- Szybki
zapis profilu do pliki *.ini
Zapewne każdy zetknął się lub wcześniej czy później zetknie się z plikami służącymi do zapisywania konfiguracji programów. Mam na myśli oczywiście pliki ustawiania konfiguracji posiadające rozszerzenie
*.ini. Pliki o których piszę wyglądają mniej więcej tak:
[NAZWA SEKCJI]
Nazwa wartości=wartość określonego typu
Nazwa sekcji to identyfikator na podstawie którego można określić położenie określonych ustawień.
Nazwa wartości to identyfikator na podstawie którego można określić położenie konkretnych wartości wewnątrz określonej wcześniej sekcji.
Wartość określonego typu to wartość będąca parametrem przechowującym jakieś wartości. Skupię się na trzech najczęściej wykorzystywanych typach wartości, mianowicie wartości znakowe do przechowywania tekstu, wartości liczbowe do przechowywania liczb, wartości typu bool służące do przechowywania wartości logicznych: 0 - fałsz & 1 - prawda.
Na razie może się to wydawać trochę skomplikowane, jednak korzystanie z plików ini jest bardzo proste i ogranicza się w zasadzie do określenia nazwy sekcji, nazwy wartości i zadanych parametrów. Zanim jednak zaczniemy korzystać z tego typu plików
należy włączyć do projektu aplikacji w pliku nagłówkowym, w sekcji include plik inifiles.hpp:
// Plik nagłówkowy np. Unit1.h //-------------------------------- #ifndef Unit2H #define Unit2H //-------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include "CSPIN.h" #include <Dialogs.hpp> #include <inifiles.hpp> //--------------------------------
|
Następnie trzeba stworzyć nowy obiekt typy TIniFile. Jeżeli chcemy żeby obiekt był dostępny dla całej aplikacji trzeba go najpierw zadeklarować w pliku nagłówkowym w sekcji private lub public, a następnie zdefiniować w pliku źródłowym w konstruktorze klasy TForm. Pójdę na łatwiznę i wszystkie przykłady wykorzystania obiektu typu TIniFile będę przedstawiał w kontekście zdarzenia OnClick dla przycisku Button1.
Tak więc deklarujemy i definiujemy nowy obiekt typu TIniFile:
// Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject* Sender) { TIniFile *PlikIni = new TIniFile("Nazwa_pliku.ini"); } //--------------------------------- |
Jak widać w przykładzie cała definicja ogranicza się do podania nazwy obiektu (w przykładzie - PlikIni - przy czym nazwa jest dowolna), oraz do określenia nazwy pliku który zawiera ustawienia programu lub do którego chcemy te ustawienia zapisać. Na początek pokażę jak należy zapisywać parametry do pliku ini (po jednym parametrze każdego typu). W tym celu umieszczamy na formularzu (np. Form1) obiekt Edit1 oraz obiekt CheckBox1, a następnie zapiszemy do pliki ini zawartość właściwości Text obiektu Edit1, właściwość Checked obiektu CheckBox1 oraz szerokość i wysokość formularza Form1:
// Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject* Sender) { TIniFile *Ini = new TIniFile("Ustawienia.ini");
Ini->WriteString("SEKCJA1", "ZawartoscEdit1", Edit1->Text); // zapisywanie tekstu do sekcji [SEKCJA1]. Ini->WriteBool("SEKCJA1", "UstawieniaCheckBox1", CheckBox1->Checked);// zapisywanie wartości true/false do sekcji [SEKCJA1]. Ini->WriteInteger("SEKCJA1", "SzerokoscForm1", Width); // zapisywanie wartości liczbowej do sekcji [SEKCJA1]. Ini->WriteInteger("SEKCJA1", "WysokoscForm1", Height); // zapisywanie wartości liczbowej do sekcji [SEKCJA1].
delete Ini; } //--------------------------------- |
Jak to widać w przykładzie cała sztuka polega na wykorzystaniu trzech funkcji:
- WriteString - zapisuje do pliku w podanej sekcji i podsekcji tekst.
- WriteBool - zapisuje do pliku w podanej sekcji i podsekcji wartości logiczne typu prawda lub fałsz.
- WriteInteger - zapisuje do pliku w podanej sekcji i podsekcji wartości liczbowe całkowite.
Podany przykład utworzy następujący plik:
[SEKCJA1] ZawartoscEdit1=Edit1 UstawieniaCheckBox1=0 SzerokoscForm1=800 WysokoscForm1=600 |
Chcąc odczytać wartości z pliku ini trzeba postąpić odwrotnie do zapisywania i posłużyć się funkcjami:
- ReadString - odczytuje z pliku tekst z podanej sekcji i podsekcji.
- ReadBool - odczytuje z pliku wartości logiczne typu prawda lub fałsz z podanej sekcji i podsekcji.
- ReadInteger - odczytuje z pliku wartości liczbowe całkowite z podanej sekcji i podsekcji.
Przy odczytywaniu danych występuje jednak pewien dodatkowy element, a mianowicie wartość domyślna, czyli jeżeli próba odczytania zawartości z pliku ini się nie powiedzie, wtedy zostaną użyte podane wartości domyślne:
// Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject* Sender) { TIniFile *Ini = new TIniFile("Ustawienia.ini");
Edit1->Text = Ini->ReadString("SEKCJA1", "ZawartoscEdit1", "tekst domyślny"); // odczytywanie tekstu z sekcji [SEKCJA1]. CheckBox1->Checked = Ini->ReadBool("SEKCJA1", "UstawieniaCheckBox1", false); // odczytywanie wartości true/false z sekcji [SEKCJA1]. Form1->Width = Ini->ReadInteger("SEKCJA1", "SzerokoscForm1", 800); // odczytywanie wartości liczbowej z sekcji [SEKCJA1]. Form1->Height = Ini->ReadInteger("SEKCJA1", "WysokoscForm1", 600); // odczytywanie wartości liczbowej z sekcji [SEKCJA1].
delete Ini; } //--------------------------------- |
W zasadzie to już prawie wszystko, na zakończenie podam jeszcze inne rzadziej stosowane funkcje obiektu TIniFile:
ReadSection
- umożliwia odczytanie nazw wszystkich podsekcji znajdujących się w podanej sekcji i przepisania ich np. do obiektów typu TMemo, TStrinList, TListBox, np:
TIniFile *Ini = new TIniFile("Plik.ini");
TStringList *txt = new TStringList;
Ini->ReadSection("SEKCJA1", txt);
ReadSections - umożliwia odczytanie nazw wszystkich sekcji w pliku i przepisania ich np. do obiektów typu TMemo, TStringList, TListBox np:
TIniFile *Ini = new TIniFile("Plik.ini");
TStringList *txt = new TStringList;
Ini->ReadSections( txt);
ReadSectionValues - umożliwia odczytanie wszystkich wartości z podanej sekcji wraz z nazwami podsekcji i przepisania ich np. do obiektów typu Tmemo, TListBox, TStringList np:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
Ini->ReadSectionValues("SEKCJA1", ListBox1->Items);
EraseSection - umożliwia usunięcie wybranej sekcji, np:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
Ini->EraseSection("SEKCJA1");
ReadDate | ReadTime | ReadDateTime | WriteDate | WriteTime | WriteDateTime - umożliwia odczytywanie | zapisywanie daty i czasu z | do pliku. Zasada stosowania jest taka sama jak w przypadku funkcji ReadString | WriteString, np:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentDate();
Ini->WriteDateTime("SEKCJA1", "DATA", Now);
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentTime();
Ini->WriteDateTime("SEKCJA1", "CZAS", Now);
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentDate();
Edit1->Text = Ini->ReadDateTime("SEKCJA1",
"DATA", Now);
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentTime();
Edit1->Text = Ini->ReadDateTime("SEKCJA1", "CZAS", Now);
ReadFloat | WriteFloat - umożliwia odczytywania | zapisywanie wartości liczbowych zmiennopozycyjnych (typu float i double) z | do pliku zasada stosowania jest dokładnie taka sama jak w przypadku funkcji ReadInteger i WriteInteger i nie wzmaga odrębnego omawiania.
SectionExists - sprawdza czy istnieje sekcja:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentDate();
if(Ini->SectionExists("SEKCJA1"))
Ini->WriteDateTime("SEKCJA1", "DATA", Now);
else
ShowMessage(Taka sekcja nie istnieje!);
ValueExists - sprawdza czy w wybranej sekcji istnieje podsekcja:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
TDateTime Now = TDateTime::CurrentDate();
if(Ini->ValueExists("SEKCJA1", "DATA"))
Ini->WriteDateTime("SEKCJA1", "DATA", Now);
else
ShowMessage(Taka sekcja i podsekcja nie istnieją!);
DeleteKey - kasuje sekcję wraz z podsekcją:
TIniFile *Ini = new TIniFile(ExtractFilePath(Application->ExeName) + "Plik.ini");
Ini->DeleteKey("SEKCJA1", "DATA");
Opracował: Cyfrowy Baron
Szybki zapis profilu do pliku *.ini.
Jak
zapisywać różnego typu wartości do plików INI jest opisane wyżej, w tej poradzie
chcę przedstawić dwie funkcje, które pozwalają na zapisanie wartości typu String
do pliku INI bez włączania do projektu biblioteki IniFiles.hpp, ale oczywiście
nie to jest zaletą tych funkcji lecz łatwość ich stosowania bez tworzenia kodu,
są to funkcje WriteProfileString(SEKCJA, KLUCZ,
WARTOŚĆ STRING), funkcja ta zapisuje dane do pliku Win.ini
znajdującego się w katalogu Windows i nie można tego zmienić, natomiast druga
funkcja: WritePrivateProfileString(SEKCJA, KLUCZ,
WARTOŚĆ STRING, NAZWA PLIKU) pozwala na zdefiniowanie
pliku do którego chcemy zapisać dane, jeżeli podamy tylko nazwę pliku bez
ścieżki dostępu, to taki plik zostanie zapisany w katalogu Windows:
// Plik źródłowy np.
Unit1.cpp. //--------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
WriteProfileString("PROFIL",
"KLUCZ",
"wartość typu String");
}
//--------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
WritePrivateProfileString("PROFIL",
"KLUCZ",
"wartość typu String",
"nazwa pliku.ini");
}
//-------------------------------- |
Niestety nie
istnieją funkcje pozwalające na równie szybki odczyt tych danych, w przykładzie
pokażę jak stworzyć własną funkcję odczytującą dane z pliku Win.ini, oczywiście
zasada jest taka sama, jak przy tworzeniu plików ini i w zasadzie na tym się
opiera:
// Plik źródłowy np.
Unit1.cpp. #include <Inifiles.hpp>
//--------------------------------
AnsiString ReadProfileString(String Profil, String Klucz)
{
char winini[_MAX_PATH];
GetWindowsDirectory(winini, _MAX_PATH);
TIniFile *Ini = new TIniFile((AnsiString)winini +
"\\Win.ini");
String Value = Ini->ReadString(Profil, Klucz,
"");
Ini->Free();
return Value;
}
//--------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
Label4->Caption = ReadProfileString("PROFIL",
"KLUCZ");
}
//-------------------------------- |
Jak widać tym
razem należy włączyć do projektu bibliotekę IniFiles.hpp.