Baza danych. Problem z zapisywaniem rekordow do pliku.

0

Witam,

Od wczoraj mecze sie ze zrobieniem bazy danych w Delphi. Rozwiazywanie roznych problemow zajmowalo mi raz mniej raz wiecej czasu. Ale teraz trafil mi sie problem, z ktorym nie moge sobie poradzic :( otóż, gdy moja baza jes jeszcze pusta i tworze pierwszy rekord, to zapisanie i odczytanie dziala dobrze. Natomiast, gdy chce juz dodac kolejny rekord to cos jest nie tak przy zapisywaniu. Ten nowy rekord zapisuje sie na swoim miejscu dobrze, ale w miejscu gdzie powinien byc poprzedni rekord jest puste miejsce. Wkleje swoj caly kod abyscie mogli znalezc przyczyne tego:

program baza;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
max=200;

type
 dane=string[50];
 samochod=record
  producent,model,rs:dane;
  rp,pojemnosc,cena:real;
 end;

plik = file of samochod;
tab=array[1..max] of samochod;

var
f:plik;
a:tab;
akt_r:word;


procedure aktualny_rozmiar(var f:plik; var a:tab; var akt_r:word);
 begin
  akt_r:=0;
  reset(f);
  while not eof(f) do
   begin
    read(f,a[akt_r]);
    akt_r:=akt_r+1;
   end;
 end;


procedure dodaj_samochod(var a:tab; akt_r:word);
 begin
  akt_r:=akt_r + 1;
  write('Producent:  ');
  readln(a[akt_r].producent);
  write('Model:  ');
  readln(a[akt_r].model);
  write('Rodzaj silnika:  ');
  readln(a[akt_r].rs);
  write('Pojemnosc silnika (litry):  ');
  readln(a[akt_r].pojemnosc);
  write('Rok produkcji:  ');
  readln(a[akt_r].rp);
  write('Cena (zl):  ');
  readln(a[akt_r].cena);
 end;

procedure zapisz_do_pliku(var f:plik; a:tab; akt_r:word);
var i:word;
 begin
  rewrite(f);
  for i:=0 to akt_r do
   begin
    write(f,a[i]);
   end;
  close(f);
 end;

procedure wyswietl(var f:plik; var a:tab);
var i:word;
 begin
  i:=0;
  reset(f);
  while not eof(f) do
   begin
    read(f,a[i]);
    inc(i);
    write(i,'. Producent: ',a[i].producent);
    writeln;
    write('   Model: ',a[i].model);
    writeln;
    write('   Rodzaj silnika: ',a[i].rs);
    writeln;
    write('   Pojemnosc silnika: ',a[i].pojemnosc:0:0,' l.');
    writeln;
    write('   Rok produkcji: ',a[i].rp:0:0);
    writeln;
    write('   Cena: ',a[i].cena:0:2);
    writeln;
    writeln;
   end;
  close(f);
 end;

begin
assign(f,'baza.txt');
aktualny_rozmiar(f,a,akt_r);
dodaj_samochod(a,akt_r);
zapisz_do_pliku(f,a,akt_r);
writeln;
wyswietl(f,a);
readln;
end.

A tu jest fotka programu jak wyglada po wlaczeniu:

http://img516.imageshack.us/my.php?image=obrazye1.jpg

na razie baza nie ma jeszcze manu, bo to zrobie na koncu jak juz wszystko mi bedzie dzialalo.

Gdyby ktos mogl mi pomoc bylbym bardzo wdzieczny. I jeszcze, gdyby ktos mogl napisac jak ma wygladac usuwanie rekordow z bazy oraz jakies sortowanie, czy wyszuiwanie.

0

źle ustawiasz akt_r.
dla jednegu już istniejącego rekordu aktualny_rozmiar ustawi akt_r=1. dodaj_samochod zwiększy na poczatku tą zmienną o 1 i będzie się odwoływać do a[2], czyli o jeden indeks za daleko.
w dodatku masz zbyt duża pętlę przy zapisie do pliku, znowu o jeden. pamietaj, że działasz od zera, czyli indeks kończący pętlę zmniejszasz o jeden.

poza tym dwie procedury masz napisane wyjątkowo niewydajnie. rozmiar bazy danych (ilość rekordów) to rozmiar pliku/wielkość rekordu, nie trzeba wykonywać ani jednego odczytu z pliku. zapis do pliku - wystarczy dodać tylko nowe rekordy, zamiast zapisywać wszystko od nowa. jak będziesz mieć kilkadziesiąt tysięcy rekordów, to baza będzie mieć okropną czkawkę.

usuwanie - na dwa sposoby - albo dorzucasz dodatkowe pole do rekordu, coś w stylu "usunięty", i potem przy odczycie nie ładujesz tych rekordów (wydajne, ale wymaga więcej niż linijki kodu), albo po prostu usuwasz takie rekordy z tablicy (a) i całość od zera zapisujesz do pliku (niewydajne!). sortowanie - zobacz sobie jak wygląda quicksort czy jakiś inny algorytm sortowania i po prostu zmień odpowiednie miejsce, żeby sortowało Twoje dane. wyszukiwanie - prosta pętla for/break albo while.

przemyśl sobie całość jeszcze raz, bo Twój kod ma dużo błędów logicznych.

0

Dzieki za pomoc :) Usunalem linijke akt_r:=akt_r+1 w procedurze dodaj_samochod i jesczze procz tego w procedurze zapisz_do_pliku przy deklaracji a:tab dodalem var. Teraz dziala elegancko ;]
Natomiast jak w petle for zmniejszylem o 1 to nie dzialalo.

rozmiar bazy danych (ilość rekordów) to rozmiar pliku/wielkość rekordu, nie trzeba wykonywać ani jednego odczytu z pliku.

Na poczatku nie mialem w tej procedurze tego read(f,a[akt_r]), ale wtedy o ile przy tworzeniu pierwszego rekordu wszystko bylo dobrze, to przy kolejnych program liczyl w nieskonczonosc rozmiar w tej petli i nie mogl z niej wyjsc, dlatego dodalem odczyt i wtedy juz normalnie liczyl.

zapis do pliku - wystarczy dodać tylko nowe rekordy, zamiast zapisywać wszystko od nowa. jak będziesz mieć kilkadziesiąt tysięcy rekordów, to baza będzie mieć okropną czkawkę.

Nie bardzo wiem jak to napisac :(

0

Na szybko naskorbałem Ci parę podpowiedzi. mam nadzieję, że pomogą.

program Project10;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;

const
  MAX_REC = 200;

type
  // Konwencja pascala - nazwy typow od T
  TSamochod = record
    Producent :string[50];
    Model     :string[50];
    Pojemnosc :Single; // Real jakos wyszedl z uzycia. Jest tylko dla
    Cena      :Single; // zachowania zgodnosci z TP
  end;

var
  // Plik amorficzny - dzieki temu mozna zapisac cokolwiek.
  // Struktura takiego pliku nie musi byc ustrukturyzowana.
  // F :file;
  // A jeszcze bardziej lubie TFileStream
  Fs       :TFileStream;
  Samochod :TSamochod;
  // Jakos z przyzwyczajenia indeksuje tablice od zera
  Baza     :array [0..MAX_REC-1] of TSamochod;
  RecCount :Word;
  Current  :Word;

begin
  // otwierasz plik do zapisu - oczytu
  FS := TFileStream.Create('Baza.db', fmOpenRead);

  // ustalenie liczby rekordow na podstawie rozmiaru pliku
  RecCount := FS.Size div SizeOf(TSamochod);

  // dopisanie kolejnego rekordu do pliku na koncu - ustawiasz wskaxnik pliku
  // na jego koniec. Inna wersja to: FS.Seek(FS.Size, foFromBeginning)
  FS.Seek(0, soFromEnd);
  FS.Write(Samochod, SizeOf(TSamochod));

  // nadpisanie dowolnego rekordu - np czwartego. Ustawiasz wskaznik na pozycje
  // o jeden mniej bo liczysz od zera
  Current := 4;
  FS.Seek((Current-1) * SizeOf(TSamochod), soFromBeginning);
  FS.Write(Samochod, SizeOf(TSamochod));

  // zapis calej tablicy
  FS.Seek(0, soFromBeginning);
  FS.Write(Baza, SizeOf(Baza));

  FS.Free();
end.

1 użytkowników online, w tym zalogowanych: 0, gości: 1