Pliki INI
Adam Boduch
1 Wprowadzenie
2 Budowa
3 Tworzenie i otwieranie
4 Edycja
5 Usuwanie kluczy
6 .NET
Wprowadzenie
Windows umożliwia zapisywanie konfiguracji w specjalnych plikach tekstowych o charakterystycznej budowie. Pliki te mają rozszerzenie .ini i zawierają informacje dotyczące konfiguracji danego programu. Sam możesz się o tym przekonać - chyba najpopularniejszym plikiem INI w Windows jest system.ini. Dzięki temu rodzajowi plików masz możliwość zapisania konfiguracji swojego programu. Jest to wygodny sposób na zapisanie jakiś danych. Wyobraź sobie program, który wymaga od użytkownika podania pewnych danych. Przykładowo będzie to imię. W takim przypadku po każdym uruchomieniu programu użytkownik byłby zmuszony do podania swojego imienia w celu dalszego użytkowania programu. Dzięki plikom INI po wpisaniu imienia na dysku może zostać stworzony plik, który zawierał będzie te informacje. Po następnym uruchomieniu programu będzie on sprawdzał, czy ten plik w określony miejscu istnieje - jeżeli tak odczytuje z niego informacje o imieniu - jeżeli nie istnieje to wyświetla okienko z informacją i wymaga podania.
Budowa
Budowa pliku INI nie jest skomplikowana. Plik INI można edytować za pomocą dowolnego edytora tekstu - nawet za pomocą notatnika. Każdy plik dzieli się na tzw. sekcje. Za pomocą tych sekcji możesz podzielić plik na poszczególne kategorie (opcje ogólne, konfiguracja, dane itp. ). Każda sekcja natomiast może zawierać klucze i wartości.
[Main]
Login=Bald
Sekcja zawsze wpisywana jest w nawiasie kwadratowym. Wszystkie klucze występujące w pliku wpisywane są pod spodem. Konstrukcja jest taka:
klucz=wartość
Pliki te mogą także zawierać komentarze. Komentarze mogą opisywać poszczególne wartości - do czego służy dany klucz i jaki efekt można osiągnąć zmieniając wartość danego klucza. Przykładowo w języku skryptowym PHP cała konfiguracja mieści się w pliku INI z którego program czyta potrzebne informacje. Chcąc więc zmienić ustawienia programu trzeba edytować plik php.ini. Żeby wiedzieć co edytować, co zmienić i co do czego służy każda wartość jest skomentowana. Komentować możesz tylko jedną linię za pomocą znaku ;
(średnik). Plik .ini może równie dobrze wyglądać tak a program i tak poradzi sobie z jego odczytem:
; Copyright (c) 2002 by Adam Boduch
;
; Jeżeli chcesz zresetowac ustawienia - usun plik setup.ini z dysku
[Main]
Login=Bald ; komentarz
Zwróć jednak uwagę na jedną rzecz. Między linią konfiguracji (klucza), a komentarzem jest przerwa. Przerwa ta jest konieczna, aby program prawidłowo odczytał dane. Przerwą w tym wypadku musi być tabulator.
Tworzenie i otwieranie
Na samym początku musisz wiedzieć jedną rzecz. Mianowicie większość plików INI jest trzymana domyślnie w katalogu Windowsa. (np. C:\Windows
). Więc tworząc plik INI musisz podać jego pełną ścieżkę... jeżeli oczywiście chcesz ten plik zapisać w innym miejscu niż katalog Windowsa. Nasuwa się więc pytanie jak pobrać np. ścieżkę naszego uruchomionego programu. Chyba nie będzie z tym problemu. Kompletną ścieżkę programu podaje funkcja ExeName, z klasy TApplication. Czyli:
S := Application.ExeName;
Zmienna S
zawiera teraz ścieżkę do uruchomionego programu - np: C:\Moje programy\2\moj_program.exe
. Teraz nasuwa się pytanie jak z tej wartości wyciągnąć tylko ścieżkę programu? Nie ma problemu. Do tego VCL udostępnia nam parę przyjemnych funkcji. (patrz tabela poniżej).
Funkcja | Opis |
---|---|
ExtractFileDir | Funkcja zwraca katalog pliku bez jego nazwy i nie zakończoną znakiem "". |
ExtractFilePath | Zwraca kompletny katalog pliku ze znakiem "" na końcu. |
ExtractShortPathName | Funkcja zwraca skróconą nazwę pliku - np: :\Progra~1\Borland\Delphi\Bin\Delphi32.exe |
ExtractFileDrive | Funkcja zwraca jedynie literę dysku na której znajduje się plik. |
ExtractFileName | Funkcja zwraca z podanej ścieżki jedynie nazwę pliku. |
ExtractFileExt | Ta funkcja natomiast podaje jedynie rozszerzenie z podanej w parametrze ścieżki. |
ChangeFileExt | Funkcja zmienia rozszerzenie pliku. |
Do operowania na plikach INI Delphi udostępnia nam wygodną klasę TINIFile. Żeby skorzystać z tej klasy należy do sekcji uses dodać moduł INIFiles . |
Na sam początek, aby skorzystać z tej klasy trzeba oczywiście wywołać jej konstruktor - zapis może wyglądać tak:
var
INI : TINIFile;
begin
INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'setup.ini');
try
{ jakieś instrukcje }
finally
INI.Free;
end;
end;
W konstruktorze tej klasy należy podać nazwę pliku INI. W tym parametrze podałem ścieżkę gdzie plik ma zostać stworzony. ExtractFilePath(Application.ExeName)
podaje jedynie lokalizację katalogów gdzie znajduje się program. Czyli w rezultacie plik znajdzie się w katalogu {nazwa_katalogu_z_programem}\setup.ini
.
Uwaga! Nie podając w tym miejscu pełnej ścieżki katalogu plik INI zostanie stworzony w katalogu z Windowsem.
Edycja
Klasa TINIFile udostępnia bardzo proste i wygodne metody, które służą do odczytu lub zapisu danych. Do pliku INI mogą być zapisane: liczby, tekst, liczby typu Double (zmiennoprzecinkowe), data i czas typu TDateTime, wartość logiczna typu Boolean oraz całe strumienie danych.
Nazwy poleceń są intuicyjne bo np. co robi metoda WriteString? Można się tego domyśleć - zapisuje tekst. A metoda, która ten tekst odczytuje? Nazywa się ReadString. Jak widzisz zamieniamy tylko słowo Write na Read a drugi człon funkcji to typ danych. Zapis nowych wartości do pliku mógłby wyglądać następująco:
INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'setup.ini');
try
INI.WriteString('Main', 'Login', Login);
finally
INI.Free;
end;
W poleceniu WriteString pierwszy parametr, który musi zostać podany to nazwa sekcji. Nie martw się - jeżeli plik nie istnieje lub nie istnieje taka sekcja w tym pliku - zostanie ona utworzona. Jeżeli natomiast istnieje - zostaną dopisane do niej nowe dane - tym nie musisz zaprzątać sobie głowy. Drugi parametr to nazwa klucza - w tym wypadku klucz nazywać się będzie Login
. Ostatni parametr to wartość tego klucza, czyli wartość która będzie przypisana do danego klucza - mam nadzieje, że tutaj jest wszystko jasne.
A co z odczytem? Zobacz:
INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'setup.ini');
try
Login := INI.ReadString('Main', 'Login', 'Adam Boduch');
finally
INI.Free;
end;
Metoda odczytująca - ReadString także posiada trzy parametry. Pierwszy to nazwa sekcji, z której dane zostaną odczytane. Drugi parametr to nazwa klucza, z którego mają być odczytane dane. Ostatni parametr oznacza wartość domyślną w przypadku, gdy klucz o podanej nazwie nie istnieje lub gdy nie istnieje sam plik INI.
Na podstawie tych poleceń możemy napisać już jakiś program, który z plików INI będzie korzystał. Np. program, który po uruchomieniu będzie sprawdzał, czy w katalogu istnieje plik setup.ini - jeżeli nie będzie wyświetlał okienko z prośbą o podanie loginu. Po wpisaniu jakiegoś loginu dane zostaną zapisane do pliku INI. Po ponownym uruchomieniu programu dane te będą widniały na formie, a żadne okienko podczas uruchamiania się nie pokaże.
W przypadku wyświetlania nowego okienka nie musimy się zajmować tworzeniem nowej formy. Moduł Dialogs.pas udostępnia do tego funkcję InputBox. Ta funkcja zwraca informację wpisaną przez użytkownika w okienku informacyjnym.
Oczywiście my sami możemy dokonać wyboru co ma się znaleźć na belce tytułowej lub wewnątrz tego okna. Można by także było w tym wypadku tworzyć nową formę, ale w tym wypadku trzeba by było oprogramować parę zdarzeń, a wiadomo - programista to człowiek leniwy...
Wywołanie funkcji InputBox może wyglądać tak:
Login := InputBox('Rejestracja...', 'Podaj login', '');
Zmienna Login
od tej pory przechowywać będzie informację wpisaną w tym oknie. Pierwszy parametr tego polecenia to tekst, który wyświetlony zostanie na belce tytułowej. Drugi parametr to tekst, który zostanie wyświetlony na komponencie Label
znajdującym się w tym oknie. Ostatni parametr to tekst domyślny w kontrolce edycyjnej Edit
. Ja w tym wypadku wpisałem ''
co oznacza tekst pusty. Wygeneruj zdarzenie OnCreate
formy i wpisz w niej taki kod:
procedure TMainForm.FormCreate(Sender: TObject);
var
INI : TINIFile;
Login : String; // login wczytany z pliku INI
begin
{ na samym początku należy sprawdzić, czy plik jest utworzony }
if not FileExists(ExtractFilePath(Application.ExeName) + 'setup.ini') then
begin
{ jeżeli nie można znaleźć pliku - wyświetl okienko z informacją z prośbą o
wpisanie swojego loginu }
Login := InputBox('Rejestracja...', 'Podaj login', '');
if Login <> '' then // sprawdź, czy login nie jest pusty
begin
{ jeżeli tak nie jest - utwórz plik }
INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'setup.ini');
try
INI.WriteString('Main', 'Login', Login); // zapisz do pliku login
lblMain.Caption := 'Witaj ' + Login;
finally
INI.Free;
end;
Exit; // nie rób już nic...
end
else
Application.Terminate; // jeżeli użytkownik nie wpisał loginu - zakończ aplikacje
end;
{ ten kod zostanie wykonany tylko wtedy, gdy plik INI został znaleziony }
INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'setup.ini');
try
Login := INI.ReadString('Main', 'Login', 'Adam Boduch'); // następuje odczyt loginu
lblMain.Caption := 'Witaj ' + Login; // następnie wyświetl login na komponencie
finally
INI.Free;
end;
end;
Przyznam się, że parę warunków If tutaj się znajduje... Użytkownik w oknie może przecież równie dobrze wpisać pusty tekst więc trzeba się przed tym zabezpieczyć i wykonać kod pod warunkiem iż tekst wpisany w kontrolce będzie różny od ''
, czyli pustego łańcucha. Ten kod zostanie wykonany w przypadku, gdy plik w katalogu z programem się nie znajduje (funkcja FileExists).
Polecenie | Opis |
---|---|
ReadBinaryStream/WriteBinaryStream | odczytuje (ReadBinaryStream) i zapisuje WriteBinaryStream) z pliku dane w postaci strumienia, trzeci parametr musi być zmienną typu TStream |
ReadBool/WriteBool | odczytuje i zapisuje dane typu Boolean, czyli True lub False |
ReadDate/WriteDate | odczytuje (ReadDate) i zapiusuje (WriteDate) wartość typu TDate |
ReadDateTime/WriteDateTime | odczytuje i zapisuje dane typu TDateTime, czyli datę i czas |
ReadTime/WriteTime | odczytuje i zapisuje w pliku jedynie czas (zmienna typu TTime) |
ReadFloat/WriteFloat | odczytuje i zapisuje dane zmiennoprzecinkowe, czyli typu Double |
ReadInteger/WriteInteger | odczytuje i zapisuje liczby (typ Integer) |
ReadString/WriteString | zapisuje i odczytuje tekst (typ String) |
W tabeli powyżej przedstawiono wszystkie metody służące do zapisywania i odczytywania danych różnych typów z pliku INI. Metody ReadBinaryStream i WriteBinaryStream są nowością w Delphi 6. |
Usuwanie kluczy
Klasa [delphi/TINIFile]] umożliwia także odczytywanie nazw sekcji lub wszystkich kluczy zawartych w sekcji. Także usuwanie nie powinno sprawić problemu, gdyż są do tego odpowiednie metody. Odczytywanie wszystkich wartości w sekcji następuje za pomocą metody ReadSections. Metoda ta odczytuje wszystkie sekcje w pliku INI do zmiennej typu TStrings. Czyli kod odczytania wszystkich sekcji mógłby wyglądać tak:
INI := TINIFile.Create('setup.ini');
Sections := TStringList.Create;
Try
INI.ReadSections(Sections);
finally
INI.Free;
end;
Po wykonaniu takiego kodu zmienna Sections
zawierać będzie wszystkie sekcje znajdujące się w danym pliku. W tym momencie każda linia zmiennej Sections
to jedna sekcja tego pliku. Odczytać ją można np. tak:
ShowMessage(Sections[0]);
Tutaj odczytujemy pierwszą linię zmiennej, czyli pierwszą sekcję.
Uwaga! W przypadku próby odczytania linii która to nie znajduje się w zmiennej wyświetlone zostanie okienko z błędem. Jeżeli np. linii w zmiennej jest 10, a Ty próbujesz odczytać 11 program wyświetli błąd: "List index out of bounds [11]".
Równie dobrze zamiast tworzyć nowy obiekt typu TStrings można od razu odczytać sekcję do komponentu - np. TListBox
:
procedure TMainForm.FormCreate(Sender: TObject);
var
INI : TINIFile;
begin
INI := TINIFile.Create('win.ini'); // odczytaj plik
try
INI.ReadSections(lblSections.Items); // wyświetl w obiekcie wszystkie sekcje
finally
INI.Free;
end;
end;
lblSections
to w tym wypadku nazwa komponentu typu ListBox
. Po kliknięciu na daną pozycję w tym komponencie można odczytać wszystkie wartości znajdujące się w tej sekcji. Wygeneruj w tym celu zdarzenie OnClick
komponentu ListBox
, a następnie wpisz:
procedure TMainForm.lblSectionsClick(Sender: TObject);
var
INI : TINIFile;
begin
INI := TINIFile.Create('win.ini');
try
lbSection.Caption := 'Sekcja: ' + lblSections.Items[lblSections.ItemIndex];
{ odczytaj do komponentu wartości wszystkich sekcji }
INI.ReadSectionValues(lblSections.Items[lblSections.ItemIndex], lblSection.Items);
finally
INI.Free;
end;
end;
Klasa udostępnia także metodę ReadSections, które to odczytuje jedynie nazwy kluczy w danej sekcji. Pierwszym parametrem w tej metodzie musi być nazwa sekcji do odczytania, a drugi parametr to zmienna typu TStrings. Ja użyłem tutaj metodę ReadSectionsValues, która odczytuje nie tylko nazwy kluczy, ale także wartości w danym kluczu zawarte.
Komponent ListBox
posiada właściwość ItemIndex
określającą numer pozycji w która jest aktualnie zaznaczona. Korzystając z tej wartości można pobrać tekst zaznaczonej w tym komponencie pozycji. W przypadku, gdy napiszesz tak:
lblSections.Items[0];
Odczytujesz pierwszą pozycję w komponencie, a żeby odczytać zaznaczoną pozycję należy w tym miejscu podstawić wartość właściwości ItemIndex
, czyli całość może wyglądać tak:
lblSections.Items[lblSections.ItemIndex]
Jak to to teraz usunąć? Jeżeli chcesz usunąć całą sekcję należy wywołać metodę EraseSection podając w parametrze nazwę sekcji - np:
INI.EraseSection('Moja sekcja');
Po takim zabiegu wszystkie klucze z danej sekcji zostaną usunięte. Możesz także usunąć pojedynczy klucz wywołując metodę DeleteKey. Ta metoda musi jedynie zawierać w parametrze nazwę klucza do usunięcia - to wszystko!
.NET
Od Delphi 8 pliki INI już nie są w tak powszechnym użyciu i ich używanie nie jest zalecane. Zamiast tego zalecane jest używanie plików XML do przechowywania danych.
Artykuł the best!
a:
TColor = TGraphicsColor;
TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF;
Nie jest to do końca to samo co integer, spróbujcie wpisać na przykłąd do TColor wartość większą od $7FFFFFFF!
Po za tym można by zadeklarować coś takiego:
TMyInteger = Integer;
Taki zapis jak wyżej to jest to samo :)
Jezu, TColor to Integer. Zrub sobie kiedyś tak:
var
I : Integer;
C : TColor;
begin
C := Form1.Color;
I := C;
end;
Pewnie pomyślisz żę wywali błąd
Incopatible types "Tcolor" and "Integer", a tu zonk. Zadziała dobrze.
Ps; możesz nawet looknąć na funkcję RGB;
Zwraca wynik w Integer;
... lub WriteColor:
:P
Mozna zrobic ReadColor IFem
Jesli to Integer to jestem eukaliptus....
TColor to przeciez Integer... nie?
FILL ->
" INI := TINIFile.Create(ExtractFilePath(Application.ExeName) + 'program.ini');
try
Form1.Left := INI.ReadInteger('00', 'X', 826);
Form1.Top := INI.ReadInteger('00', 'Y', 0);
Form1.Width := INI.ReadInteger('00', 'Xsize', 199);
Form1.Height := INI.ReadInteger('00', 'Ysize', 488);
finally
INI.Free;
end;
"
Odpowiedź na Twoje pytanie dużo niżej.
tomalla ->
"INI.WriteString('sekcja','klucz',Memo1.Lines.Text);"
Mi się podoba ten artykuł.
:P
Procek ->
"ExtractFilePath(Application.ExeName);"
Mam pytanie. Jak zapisać kolor do pliku INI. ReadColor nie istnieje. Nie ma czegoś takiego jak ColorToStr :/
???
@mr_Zola
a co za różnica czy Windows czy biblioteki? Istnieje jakiś format plików czy to mp3 czy doc i są programy je obsługujące ja podobnie postrzegam pliki ini.. czyżbym się mylił ?? :P
@tomalla
"ReadColor" nie ma .. ale możesz sama napisać ;P
@procek
raczej nie lepiej... bo zwraca aktualny katalog nie katalog programu, więc np. odpalając ten program w dosie lub zmieniając w skrócie właściwość "Rozpocznij w" zwróci inną ścieżkę
A nie lepiej GetCurrentDir ??
A mam jeszcze jedno pytanko - Czy jest coś w stylu ReadColor? Otóż chcę żeby mi wczytał kolor z pliku INI. Na przykład:
...
Form1.Color := INI.Read...?...('General', 'Color', clBtnFace);
...
Proszę o szybką odpowiedź
"Windows umożliwia zapisywanie konfiguracji w specjalnych plikach tekstowych o charakterystycznej budowie..."
czy to windows umożliwia czy może jakaś biblioteka?
Ja tam zadnej tabelki nie widze :P
W kazdym razie tutaj (Rozdział 6) masz bardziej rozbudowany tekst o INI. Moze Ci pomoze.
jest tu tabelka ze zmiennymi, jakie można wpisać do tego ini, np. writeinteger itd, ale jak można tam wpisać zmienną tstring? dokładniej z memo?!?!
odswiezam art jak dla mnie super pomocny Panie Adamie tak trzymac!!!
A mi nie działa 'Application.ExeName', ale wpisalem 'ParamStr(0)' i jest :P
Snowak: no to sie troche spóźniełeś.... jakieś 2 lata
:/
buuuuuuuu! A ja wlasnie chcialem o tym arta napisac!
no...<ort>artykół</ort> nie taki zły.
Dzienki temu <ort>artykółowi</ort>, moje progi mają ustawienia, własciwości, konfiguracje....
Tylko nie wiem czy to ten sam co kiedyś czytałem, bo w tamtym była tabelak z możliwościami innymi niż tylko WRITE i READ strin i integer.
Dużo też sam doszedłem, ale bardzo szybko.
Wystarczy zrozumieć o co chodzi i ze wyszystkim innym (readbool, i inne) jest tak samo.
Artykul do bani. Jezuuu, ja to pisalem????
W której procedurze wczytać położenie formy wcześniej zapisane w ini?
'01' to nazwa klucza - w programie nie ma to takiego znaczenia, gdyz moze byc jakakolwiek.
czy w pliku muszą być '01' itd. ?
a jak przeszukac plik, jesli zawiera w sobie dpa=dpsko to zeby odczytalo d*psko do zmiennej ?? napisz na szkola81@go2.pl
narq