Bazy danych oparte na własnych formatach
Wolverine
Wstęp
Wielu z nas zapewne zastanawiało się nad stworzeniem prostej bazy danych, czy to opartej na plikach tekstowych czy typowanych. Ostatecznie rzucaliśmy projekt i sięgaliśmy pomocy ze strony popularnych systemów bazodanowych (np. MySQL), lecz to rozwiązanie ma jedną podstawową wadę - wymagania ze strony komercyjnego Delphi.W tym artykule pragne przybliżyć tworzenie baz danych opartych na dwóch wyżej wymienionych sposobach: pliki tekstowe i pliki typowane. Obie metody mają swoje zalety i wady.
Proste pliki tekstowe
Główna zaletą plików tekstowych jest ich prosta konstrukcja, najprostrza zawartość pliku takiej bazy może wyglądać tak:Jan|Kowalski|Kasztanowa|8|1|Warszawa
Jedynym zadaniem programu odczytującego taki plik bedzie podzielenie linijki względem znaku |.
procedure Explode(s: String; Dot: Char; var Buffer: TStringList);
begin
Buffer.Clear;
while Pos(Dot, s) <> 0 do begin
Buffer.Add(Copy(s, 1, Pos(Dot, s) - 1));
s := Copy(s, Pos(Dot, s) + 1, Length(s) - Pos(Dot, s));
end;
if Length(s) > 0 then begin
Buffer.Add(s);
end;
end;
Procedura dzieli linie, podawaną w parametrze s (String) na liste łańcuchów względem znaku Dot (Char) i zapisuję ją w parametrze Buffer (TStringList). Teraz mamy wszystko, aby stworzyć pierwszy, prosty program wykorzystujący tekstowe bazy danych.
Przykładowy odczyt może wyglądać tak:
var
Rec, Baza: TStringList;
i: Integer;
begin
Baza := TStringList.Create;
Rec := TStringList.Create;
Baza.Lines.LoadFromFile('plik z baza');
for i := 0 to Baza.Lines.Count -1 do begin
Explode(Baza.Lines[i], '|', Rec);
Memo1.Lines.Add('Imie: ' + Rec[0]);
Memo1.Lines.Add('Nazwisko: ' + Rec[1]);
end;
end;
Hyper Objects Language
Drugim formatem bazy w plikach tekstowych, ktory zamierzam opisać w tym artykule jest plik HOL (Hyper Objects Language). Format pliku jest zbliżony do formatu pliku ini, lecz opiera się na pseudo-obiektach. Przykładowy plik HOL wygląda tak:hol;version=100;Author=Wolverine
user;imie=Jan;nazwisko=Kowalski;ulica=Kasztanowa;numer domu=8;numer mieszkania=1;miasto=Warszawa
Druga linijka informuje program przetwarzający o wersji skryptu, w tym przypadku 1.0.0 (100). Mimo pozorów odczytanie informacji z takiego pliku będzie łatwiejsze i wygodniejsze niż w poprzednim przypadku. Jedną z zalet skryptów HOL jest ich odporność na położenie danych, np:
user;imie=Jan;nazwisko=Kowalski
da ten sam efekt co:
user;nazwisko=Kowalski;imie=Jan
Do odczytania pliku posłuży nam kasa THolFile (załączona do artykułu). Po rozpakowaniu archiwum do naszego programu możemy dodać odpowiedni modów do naszego programu
uses HolFile;
i zadeklarować zmienna parsera
var
HolFile: THolFile;
Jak każdą klase THolFile trzeba przed użyciem stworzyć
HolFile := THolFile.Create;
Następnie można załadować plik z bazą danych
HolFile.Parse('Nazwa pliku');
Od tego momentu mamy do dyspozycji zawartość naszej bazy, jest ona przechowywana w tablicy HolObjects (array of THolObject). Pojedyńczy obiekt ma właściwość name (nazwa) i kolejną tablice - params (array of THolParam). Gdy znamy już podstawowe elementy budowy klasy THolFile, możemy użyć jej do wczytania pliku z danymi
var
HolFile: THolFile;
i: Integer;
begin
HolFile := THolFile.Create;
HolFile.Parse('nazwa pliku');
for i := 0 to HolFile.ObjectCount -1 do begin
Memo1.Lines.Add('Imie: ' + GetParamValue(HolFile.HolObjects[i], 'imie');
Memo1.Lines.Add('Nazwisko: ' + GetParamValue(HolFile.HolObjects[i], 'nazwisko');
end;
HolFile.Free;
end;
Kod może wydawać się trudniejszy, ale jest bardziej elastyczny i za pomocą specjalnych metod klasy THolFile można np zdefiniować ze zmiennej, jakie dane mają zostać wczytane, podczas gdy w poprzednim rozwiązaniu mieliśmy dostępne dane w postaci rygorystycznie ustawionej listy.
Pliki typowane
Jest to najtrudniejsze i najmniej elastyczne rozwiązanie z trzech przedstawionych, ale równie często używane przez programistów. Plików typowanych nie da się edytować w edytorze tekstowym, co sprawia, że ten rodzaj bazy jest najbezpieczniejszy. Ich zawartość tworzą rekordy definiowane na stałe w programie. Przykładowy rekord może wyglądać tak:TUser = record
Imie: String[20];
Nazwisko: String[30];
Ulica: String[20];
end;
Jak można zauważyć w rekordzie możemy zdefiniować zmienne, lecz z pewną zasadą - każdy rekord musi mieć jednakową wielkość. A więc plik typowany jest zbiorem rekordów, ktore są zbiorami ze ściśle określonymi zmiennymi, ale jak ich używać?
Nie ma uniwersalnej klasy do obsługi każdego pliku typowanego, jest za to obiekt file (plik), który przypomina po części tablice. Definiuje się go tak samo
Baza: file of TUser;
Po zdefiniowaniu typu należy przypisać mu fizyczny plik
AssignFile(Baza, 'nazwa pliku');
Aby zacząć korzystanie plik należy zainicjować
Reset(Baza);
Gdy chcemy edytować plik
ReWrite(Baza);
Gdy chcemy go stworzyć od początku
Do odczytu rekordu z pliku służy procedura Read, która za parametry obiera odczytywany plik i zmienną do zapisu
type
TUser = record
Imie: String[20];
Nazwisko: String[30];
Ulica: String[20];
end;
var
User = TUser;
Baza: file of TUser;
begin
AssignFile(Baza, 'nazwa pliku');
ReWrite(Baza);
while not Eof(Baza) do begin
Read(Baza, User);
Memo1.Lines.Add('Imie: ' + User.Imie);
Memo1.Lines.Add('Nazwisko: ' + User.Nazwisko);
end;
Close(Baza);
end;
Zapis do pliku wygląda analogicznie, używając procedury Write, przybierającej jako parametry plik i rekord do zapisu. Wadą (?) plików typowanych jest programowanie niskopoziomowe, które dla niedoświadczonych programistów może okazać się niewygodne.
Na zakończenie
Wszystkie trzy metody nadają się wspaniale do obsługi małych aplikacji bazodanowych, lecz należy zapamiętać, że każdy z nich ma pewne wady: mała elastyczność przy prostych plikach tekstowych, brak wbudowanych metod szyfrujących w klasie THolFile i konieczność programowania niskopoziomowego przy plikach typowanych. Mam nadzieję, że każdy znajdzie w tym artykule coś dla siebie.Pliki
Pliki do artkułu: [HOL_Parser_v100.zip](//4programmers.net/Download/372/937)Dodatkowe informacje:
4p - Pliki typowane
Delphi.About.com - My own database
Jest jeszcze jedna bardzo duża niedogodność. Szukanie odpowiedniego rekordu ;>
Na szczęście istnieje coś takiego jak SQLite, dzięki czemu już się nikt nie musi bawić we własne formaty baz danych i może używać SQLa :)
B.d artykuł :)
a jak załadować to do DBGrida?
Ja podchodzę do zagadnienia trochę inaczej. Na początku tworzę odpowiednie rekordy, np:
Odczyt/zapis poprzez BlockRead/BlockWrite. Tworzenie i niszczenie przez New i Dispose.
Skad pobrac ten HOL Parser, bo ten link nie dziala?
*Juz mam http:*4programmers.net/file.php?id=1506
Rookie One ~ przez wieki uzytkowania nie zdarzylo mi sie cos takiego ...
Ta procedurka Explode jest delikatnie mowiac zryta (wywoluje naruszenie dostepu). Dajcie sobie z nia spokoj i uzyjcie tej.
dobry art
terz ostatnio się w tym babram i co do plików typowanych to niemasz całkiem racji prawdą jest, że otworzenie takiego pliku w notatniku ukaże nam ciąg niezrozumiałuch znaczków jednak po dłuższym siedzeniu w tym można cokolwiek rozgryźć ale zapis dokonanych zmian to jednak nadal ryzykowna decyzja
ja zrobilem baze danych oparta o pliki ini, prosty program, robiony przeze mnie i oczywiscie nie skonczony
? a co wlasciwie zmieniles? bo ja roznicy nie widze :/
Mam Delphi6 i umnie to nie chodzi, trzeba odrobinę kod zmodyfikować:
procedure pobierzdane(s: String);
var
Rec, Baza: TStringList;
i: Integer;
begin
Baza := TStringList.Create;
Rec := TStringList.Create;
Baza.LoadFromFile(s);
for i := 0 to Baza.Count -1 do begin
Explode(Baza.Strings[i], '|', Rec);
end;
end;
Teraz jest ok!
racja, poprawione.
Czemu używasz słowa kluczowego do nazwy zmiennej.. to nie ma prawa działać.