Start med INI filer - part 2

Tags:    delphi
Skrevet af Bruger #1425 @ 26.10.2002
En indføring til INI filer – Part II


Indledning

Denne artikel vil gennemgå 4 ting:
  1. Lidt basal fejlhåndtering vha. TINIFile objektet.
  2. Hvordan man kan liste sektioner og nøgler, eventuelt med deres tilhørende data. Først med et simpelt eksempel, derefter med et eksempel der ligger noget tættere på hvordan man benytter dem i ”virkeligheden”
  3. Hvordan man sletter data i filen
  4. Lidt blandede informationer.

Fejlhåndtering under læsning

Her er der to slags fejl vi skal være opmærksomme på:
  1. At det vi søger ikke kunne findes i filen
  2. At det data vi henter ikke er gyldigt (F.eks.hvis vi forsøger at hente et stykke tekst med ReadInteger).

Det første tilfælde klares nemt, da Delphi's programmører har været så flinke at implementere 2 funktioner til dette:
SectionExists og ValueExists. Disse demonstreres bedst med et eksempel (som benytter INI filen fra part I. Har du ikke den liggende kan du hente den her)
  //function SectionExists(Const Section: String): Boolean;
  If MyINI.SectionExists('MinSektion') Then
    ShowMessage('Sektionen ''MinSektion'' blev fundet i filen')
  else
    ShowMessage('Sektionen ''MinSektion'' blev ikke fundet');

  //function ValueExists(Const Section, Ident: String): Boolean;
  If MyINI.ValueExists('MinSektion', 'BlaBla') Then
    ShowMessage('Nøglen ''BlaBla'' under ''MinSektion'' blev fundet i filen')
   else
    ShowMessage('Nøglen ''BlaBla'' under ''MinSektion'' blev ikke fundet i filen');
Her checkede vi først om sektionen MinSektion fandtes, hvilket den jo gjorde hvis du brugte filen fra part I.
Dernæst så i om nøglen BlaBla under MinSektionfandtes, hvilket den ikke gjorde.

Dette er en effektiv metode til at se om ens program har fået gemt indstillinger, eller om det skal spørge brugeren efter oplysninger.
Note: Man kan jo selvfølgelig bruge funktionen FileExiststil at checke om ens INI fil findes, men ovenstående metode er grundigere.Eks:
  If FileExists('test.ini') Then
    ShowMessage('test.ini findes!')
   Else
    ShowMessage('test.ini blev ikke fundet!');  
note: FileExists søger i programmets sti hvis en absolut sti ikke bliver angivet.

Det andet tilfælde må klares med Default I vores Read* funktioner, da man ikke har mulighed for entydigt at bestemme om en nøgle er af den ene eller anden værdi. Hvis vi tager vores INI fil fra part i igen, og forsøger med
  ShowMessage(IntToStr(MyINI.ReadInteger('MinSektion', 'Tekst', 0)));
vil vi få en message box med teksten ’0’, da ’ Se, det virker!’ som ligger under nøglen ’Tekst’ ikke er en gyldig heltals værdi.

Hvis man af den ene eller anden grund ikke kan læse fra filen(f.eks. har man ikke adgang til den), returneres Default værdien.

Fejlhåndtering ved skrivning

Når vi skriver til en fil er det eneste vi skal være opmærksomme på er af vi rent faktisk kan skrive til filen. Ja, det lyder dumt, men der er par mulige forhindringer:
  1. Filen kan være låst af et andet program
  2. Der kan være for lidt ledig plads til at gemme data
Disse begivenheder optræder ikke særligt tit, jeg har selv aldrig været ude for det, men jeg vil alligevel give et hint til hvordan man kan undgå at ens program går ned med en fejlmeddelelse. Vi klarer dette ved at trappe fejlen med en Try..Except..End statement, denne bliver illustreret med et eksempel:
  Try
    MyINI.WriteString('EnSektion', 'EnNøgle', 'en hel del data her, som ikke kan skrives af den ene eller anden grund. ');
  Except
    On EINIFileException do
    Begin
      //Der opstod en fejl!!
      ShowMessage('Fejl: Data kunne ikke skrives til filen.');
    End;  
  End;
Hvis du vil teste hvordan dette fungerer, kan du hente et program her til at låse en fil for at udløse en fejl med TINIFile objektet. Bemærk: Hvis man forsøger at trappe fejlen i Delphi’s udviklingsmiljø kommer der stadig en fejl box, det gør der ikke i den kompilerede exe fil.

Dette er hvad vi har brug for at kunne håndtere de fejl der måtte opstå i forbindelse af TINIFile objektet.

Listing af indhold - indledning

De metoder vi skal bruge for at liste indhold er følgende:
  • Procedure ReadSections(Section: TStrings);
  • Procedure ReadSection(Const Section: String; Keys: TStrings);
  • Procedure ReadSectionValues(Const Section: String; Values: TStrings);
De har 1 eller 2 parametre, Section er som bekendt sektionen vi arbejder med. Den anden parameter har vi ikke mødt før, den er erklæret som værende af typenTStrings, som er en streng liste. Det er her i procedurerne ”returnerer” data. Procedurne bliver gennemgået først hver for sig i den rækkefølge de blev listet ovenfor. Disse eksempler tager udgangspunkt i filen fra part I, og benytter en TlistBox(Kald den Listbox1) på en form.

Listing af indhold - eksempler


Listing af sektioner:
    MyINI.ReadSections(Listbox1.Items);
Så skulle vores listbox vise:
MinSektion
EndnuEnSektion

Det var jo meget let :) så vi går straks videre med de 2 andre metoder.

Listing af nøgler
  MyINI.ReadSection('MinSektion', Listbox1.Items);
Nu viser listbox’en:
Tekst
Heltal



Listing af nøgler og værdi
  MyINI.ReadSectionValues(’MinSektion’, Listbox1.Items);
Nu viser listbox’en:
Tekst=Se, det virker!
Heltal=1337

Nu har vi lært at liste indhold fra en INI fil, men her kommer alligevel et eksempel mere det lister filen i listbox’en efter formatet
sektion
   nøgle  -  værdi
Formålet med dette er at vise hvordan man kan loope igennem filen og arbejde med de enkelte nøgler og sektioner i loopet. Her bliver brugt et par ting som ikke direkte omhandler INI filer, men de bør forklares i konteksten alligevel:
Var
  MyINI: TINIFile; // TINIFile objektet
  PathToINIFile: String;
  I,J:Integer;
  Sections, Keys: TStringList; //TString lister
Begin
  Listbox1.Clear;

  PathToINIFile := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0)))+'test.ini';

  {Skab objektet}
  MyINI := TINIFile.Create(PathToINIFile);

  {skab TStrings objekter}
  Sections := TStringList.Create;
  Keys := TStringList.Create;

  {Læs sektioner}
  MyINI.ReadSections(Sections);

  {Loop igennem sektionerne}
  For I := 0 to Sections.Count -1 do
  Begin
    {læs nøgle navne}
    MyINI.ReadSection(Sections.Strings[I], Keys);

    {tilføj til listbox}
    Listbox1.Items.Add(Sections.Strings[I]);

    {loop igennem nøgler}
    For J := 0 to Keys.Count -1 do
    Begin
      {tilføj til listbox}
      Listbox1.Items.Add('  '+Keys.Strings[J]+
                         '  -  '+MyINI.ReadString(Sections[I], Keys[J], ''));
    End; //FOR J
  End; ///FOR I

  {frigør objekter}
  MyINI.Free;
  Sections.Free;
  Keys.Free;
Det nye er TStringList objekterne. Nu skaber vi dem i koden, da de blot skal bruges midlertidigt til at holde sektioner og nøgler. På disse objekter bruger vi kun Strings og Count. Count returnere hvor mange strenge objektet indeholder. Strings er strenglisten. For at få fat i en streng skal vi bruge dens index nummer. For den første streng bruges MinListe.Strings[0], nummer 2 er MinListe .Strings[1] og så videre. Man kan nøjes med at skrive MinListe[IndexNummer] for at få fat i strengen. Så bruger vi For loops til at loope igennem sektionerne og nøglerne, for derefter at opstille dem i en ListBox. Husk altid at frigøre dine objekter igen!

Dette er hvad vi skal bruge for at kunne liste indholdet af ini filer.

At slette fra en INI fil

Dette har vi to funktioner til:
  1. procedure DeleteKey(const Section, Ident: String);
  2. procedure EraseSection(const Section: String);
DeleteKey – At slette en nøgle procedure DeleteKey(const Section, Ident: String);
  MyINI.DeleteKey('MinSektion', 'Tekst');
Denne har to parametre, sektionen nøglen ligger i og nøglen der skal slettes. Denne linie ville slette nøglen ’Tekst’ under ’MinSektion’. EraseSection – At slette en hel sektion
 MyINI.EraseSection('MinSektion');
Denne har en parameter, nemlig sektionen der skal slettes. Linien her vil slette sektionen ’MinSektion’;

Lidt blandede informationer

Denne sektion indeholder lidt informationer der ikke rigtigt passede ind andre steder…
Andre egenskaber på TINIFile objektet
Filename - Dette er en read-only property, og kan hele tiden fortælle os hvilken fil vi arbejder med.
Der er også nogle Read og Write funktioner jeg ikke har nævnt, disse er: ReadTime, ReadDate, ReadDateTime og ReadBinaryStream. De tre første fungerer som funktionerne omtalt i part I. ReadBinaryStream kræver et TStream objekt som den kan skrive til, princippet er det samme som vist under Listing af indhold. Jeg har valgt ikke at have eksempler med disse funktioner da jeg aldrig selv har haft brug for dem.

Afrunding

Dette var så part II af en indføring til INI filer. Der er lavet et tilhørende demo projekt som kan hentes på http://code.loftager.dk/udv/ini/ini_part_ii.zip. Dette projekt indeholder eksemplerne fra denne artikel. Programmet til at låse en fil kan findes http://code.loftager.dk/udv/ini/lockfile.zip
Eventuelle spørgsmål kan stilles enten via mail eller Udvikleren’s IRC kanal.



Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (2)

User
Bruger #3530 @ 03.09.03 22:59
Flot artikel...men men ....thomas jeg kunne nu bedre lide version 1 :D nok pga. denne mest er bygget over fejlhåndtering men det med at slette er rigtig godt
User
Bruger #10266 @ 11.02.08 14:54
God artikel!
Jeg har den altid i baggrunden, hvis jeg skal programmere med en INI fil (; 4 herfra.
Du skal være logget ind for at skrive en kommentar.
t