Zapisywanie rekord do pliku oraz ich odczyt w programie.

0

Witajcie!
Staram się napisać program w Delphi 7 dotyczący zapisu do pliku oraz jego odczytu. Problem w tym, że nie wiem czemu zapis mi nie działa tzn. w pliku pojawiają się jakieś "ślaczki". Jeśli są to błędy "nowicjusza" to bardzo przepraszam niestety sam tego nie potrafię przeskoczyć.

program faktura;
   
{$APPTYPE CONSOLE}

uses
  SysUtils;

type faktura=record
             imie:String[15];
             naz:string[25];{nazwisko}
             nazwa:String[100];{artykuły}
             cena:integer;
             ilosc:integer;
             data:string[10];
             art:integer;
end;
type dane=array of faktura;
type t=array[1..20] of faktura;

procedure wprowadzanie(var wprow:faktura);  {wprowadzanie danych z faktury}
begin
Writeln('Dane kupujacego');
Writeln('Podaj imie: ');
                    readln(wprow.imie);
Write('Podaj nazwisko: ');
                    readln(wprow.naz);
                    Writeln(' ');
Writeln('Data Wystawienia');
Write('Podaj date wystawienia faktury (dzien-miesiac-rok): ');
                    readln(wprow.data);
                    Writeln(' ');
writeln('Artykuly');
writeln('Ilosc artykulow: ');
                    readln(wprow.art);
writeln('Podaj nazwe artykulu: ');
                    readln(wprow.nazwa);
write('Podaj cene artykulu: ');
                    readln(wprow.cena);
write('Podaj ilosc: ');
                    readln(wprow.ilosc);
end;

procedure wypisywanie(wprow:faktura);
          var c1:integer;
                        begin
Writeln('Imie: ',wprow.imie,'              Nazwisko: ',wprow.naz);
                          writeln(' ');
Writeln('Data wystawienia: ',wprow.data);
                          writeln(' ');
Writeln('Nazwa artykulu: ',wprow.nazwa);
Writeln('Cena artykulu: ',wprow.cena);
Writeln('Ilosc: ',wprow.ilosc);
c1:=wprow.cena*wprow.ilosc;
Writeln('Cena: ',c1);
                                end;

procedure zapisz(wprow:faktura);                       {===============}
          var p:text;
              nazwa_pliku:String;
              i:integer;
              ile:integer;
              a:t;
              begin
              write('Podaj nazwe pliku do zapisu: ');
                read(nazwa_pliku);
                  assign(p,nazwa_pliku);
                    rewrite(p);
                    write(p,a[i].imie,a[i].naz);
                   
                    close(p);  {zamknięcie pliku}
              end;

procedure wczytanie(wprow:faktura);
         var p:text;
             nazwa_pliku:String;
              a:t;
             var i:integer;
             begin
                   write('Podaj nazwe pliku do odczytu: ');
                   readln(nazwa_pliku);
                     assign(p,nazwa_pliku);
                         reset(p);
                           ilosc:=0;
                           while not(eof(p)) do
                               begin
                                  ilosc:=ilosc+1;
                                  read(p,a[i].imie,a[i].naz);
                                
           close(p);

end;
var wprow:faktura;
var a:t;
var i,ile:integer;
var b:dane;
var c:faktura;
begin

writeln('Ile faktur? ');
readln(ile); 
for i:=1 to ile do
begin
                   wprowadzanie(a[i]);
end;
writeln(' ');
for i:=1 to ile do
begin
                    wypisywanie(a[i]);
                    
end;
readln;
zapisz(wprow);
wczytanie(wprow);
write(a[i].imie,' ',a[i].naz);
readln;
end.
0

Nie mam siły tego czytać. Ale skoro już masz coś takiego:

type faktura=record
             imie:String[15];
             naz:string[25];{nazwisko}
             nazwa:String[100];{artykuły}
             cena:integer;
             ilosc:integer;
             data:string[10];
             art:integer;
end;

to czemu by nie zrobić:

plik : File of faktura
0

Przede wszystkim, jeśli już chcesz zapisać rekord do pliku to nie korzystaj z plików tekstowych, bo sam sobie utrudnisz pracę; Albo skorzystaj z podpowiedzianych przez @babubabu plików typowanych, albo wykorzystaj pliki amorficzne i procedury BlockWrite i BlockRead - dzięki temu będziesz mógł jedną instrukcją zapisać oraz odczytać cały rekord; Jeśli wolisz typowane - dobrze, że określiłeś długość łańcuchów w polach rekordu, bo jest to nieodzowne do poprawnego wykorzystania tego typu plików;

Na przyszłość więcej czytaj i testuj, tymczasem wątek przenoszę do działu dla początkujących, bo dotyczy podstaw operowania na plikach;


A co do Twojego kodu to zapewne problem jest w procedurze zapisu:

procedure zapisz(wprow:faktura);                       {===============}
          var p:text;
              nazwa_pliku:String;
              i:integer;
              ile:integer;
              a:t;
              begin
              write('Podaj nazwe pliku do zapisu: ');
                read(nazwa_pliku);
                  assign(p,nazwa_pliku);
                    rewrite(p);
                    write(p,a[i].imie,a[i].naz);
 
                    close(p);  {zamknięcie pliku}
              end;

pomijam już formatowanie i nazwy identyfikatorów zmiennych itd., ale zwróć uwagę co i jak zapisujesz - łączysz imię i nazwisko w jeden ciąg w jednej linii, więc nie możesz go później z powrotem rozdzielić; Brakuje także zapisu pozostałych pól ze struktury (nie wiem czy to specjalnie, ale dla mnie to niedopatrzenie chyba, że kod jeszcze nie jest skończony);


Edit: Problem jest oczywisty - wcześniej nie zauważyłem, bo nazewnictwo zmiennych jest nienajlepsze, tak samo jak formatowanie kodu, ale dotyczy dokładnie tej linii:

write(p,a[i].imie,a[i].naz);

Wykorzystujesz do zapisu niezainicjowaną zmienną a: t; Tłumacząc łopatologicznie - zmienną masz zadeklarowaną, ale przed zapisem nie wpisujesz do niej żadnych danych, stąd w pliku lądują śmieci;

0
furious programming napisał(a):

Przede wszystkim, jeśli już chcesz zapisać rekord do pliku to nie korzystaj z plików tekstowych, bo sam sobie utrudnisz pracę; Albo skorzystaj z podpowiedzianych przez @babubabu plików typowanych, albo wykorzystaj pliki amorficzne i procedury BlockWrite i BlockRead - dzięki temu będziesz mógł jedną instrukcją zapisać oraz odczytać cały rekord; Jeśli wolisz typowane - dobrze, że określiłeś długość łańcuchów w polach rekordu, bo jest to nieodzowne do poprawnego wykorzystania tego typu plików;

Na przyszłość więcej czytaj i testuj, tymczasem wątek przenoszę do działu dla początkujących, bo dotyczy podstaw operowania na plikach;


A co do Twojego kodu to zapewne problem jest w procedurze zapisu:

procedure zapisz(wprow:faktura);                       {===============}
          var p:text;
              nazwa_pliku:String;
              i:integer;
              ile:integer;
              a:t;
              begin
              write('Podaj nazwe pliku do zapisu: ');
                read(nazwa_pliku);
                  assign(p,nazwa_pliku);
                    rewrite(p);
                    write(p,a[i].imie,a[i].naz);
 
                    close(p);  {zamknięcie pliku}
              end;

pomijam już formatowanie i nazwy identyfikatorów zmiennych itd., ale zwróć uwagę co i jak zapisujesz - łączysz imię i nazwisko w jeden ciąg w jednej linii, więc nie możesz go później z powrotem rozdzielić; Brakuje także zapisu pozostałych pól ze struktury (nie wiem czy to specjalnie, ale dla mnie to niedopatrzenie chyba, że kod jeszcze nie jest skończony);


Edit: Problem jest oczywisty - wcześniej nie zauważyłem, bo nazewnictwo zmiennych jest nienajlepsze, tak samo jak formatowanie kodu, ale dotyczy dokładnie tej linii:

write(p,a[i].imie,a[i].naz);

Wykorzystujesz do zapisu niezainicjowaną zmienną a: t; Tłumacząc łopatologicznie - zmienną masz zadeklarowaną, ale przed zapisem nie wpisujesz do niej żadnych danych, stąd w pliku lądują śmieci;

Prawda jest taka, że zapis jest nieukończony przez to, że "nie działa" poprawnie i nie wiem jak to poprawić. Co do zapisu danych do zmiennej to miałem zamiar by były wprowadzane tu:

procedure wprowadzanie(var wprow:faktura);  {wprowadzanie danych z faktury}
begin
Writeln('Dane kupujacego');
Writeln('Podaj imie: ');
                    readln(wprow.imie);
Write('Podaj nazwisko: ');
                    readln(wprow.naz);
                    Writeln(' ');
Writeln('Data Wystawienia');
Write('Podaj date wystawienia faktury (dzien-miesiac-rok): ');
                    readln(wprow.data);
                    Writeln(' ');
writeln('Artykuly');
writeln('Ilosc artykulow: ');
                    readln(wprow.art);
writeln('Podaj nazwe artykulu: ');
                    readln(wprow.nazwa);
write('Podaj cene artykulu: ');
                    readln(wprow.cena);
write('Podaj ilosc: ');
                    readln(wprow.ilosc);
end;
 

Śmiem twierdzić, że chyba nie są przekazywane dalej. Co do nazw zmiennych to będę musiał je pozmieniać bo pomimo tego , że wiem o co chodzi czasem można się pogubić.
a:t <== chciałem tym móc przekazywać kilka osób oraz artykułów.

0

Od d**y strony się zabierasz

0
liberate1792 napisał(a)

Prawda jest taka, że zapis jest nieukończony przez to, że "nie działa" poprawnie i nie wiem jak to poprawić.

Jeśli już uparłeś się na pliki tekstowe, to zapisuj kązde pole rekordu w osobnej linii tak, by można było je z powrotem odczytać; Zarówno @babubabu zasugerowaliśmy Ci wykorzystanie plików typowanych, bo dzięki temu zapiszesz oraz odczytasz cały rekord jedną instrukcją Read, ale Ty dalej wolisz pliki tekstowe; Podobnie było by jeśli chodzi o pliki amorficzne, jednak tam dodatkowo trzeba znać rozmiar typu rekordu, co oczywiście nie jest żadnym problemem - wystarczy wywołać funkcję SizeOf(TypRekordu) i gotowe;

liberate1792 napisał(a)

Śmiem twierdzić, że chyba nie są przekazywane dalej.

Są przekazywane "dalej" jeśli chodzi Ci o widoczność poza ciałem procedury - zadeklarowany masz przecież argument var wprow: faktura, dzięki temu wpisując dane do struktury odwołujesz się do zewnętrznej zmiennej przez referencję i tak po zakończeniu wykonywania tej procedury wartości jakie zostały podane są ustalone w zewnętrznej zmiennej (jeśli chodzi o kod z ostatniego Twojego posta);

liberate1792 napisał(a)

a:t <== chciałem tym móc przekazywać kilka osób oraz artykułów.

Mógłbyś to zrobić, ale nie w ten sposób; Zmienną co prawda masz zadeklarowaną, jednak nie wpisujesz do niej żadnych danych, nawet nie zerujesz zawartości tej zmiennej, a potem zapisujesz ją do pliku, stąd lądują do pliku randomowe śmieci; Jeśli chcesz zapisać zawartość faktury do pliku, to wykorzystaj przekazany argument wprow:faktura) w procedurze zapisz, a nie zmienną a, która jak widać do niczego w tym kodzie nie służy; W ogóle ten kod jest źle zaprojektowany - panuje w nim haos i ciężko wyczuć co w ogóle chcesz zrobić;

Jeśli chcesz zapisać wszystkie faktury to operuj na zmiennej a: t, którą masz zadeklarowaną globalnie - najlepiej to przekazuj ją w argumencie procedury zapisz i w pętli zapisuj po kolei każdy rekord do pliku tekstowego lub typowanego, albo całą tablicę jednorazowo procedurą BlockWrite jeśli chodzi o pliki amorficzne (lub jak wolisz także w pętli);

0
furious programming napisał(a):

Mógłbyś to zrobić, ale nie w ten sposób; Zmienną co prawda masz zadeklarowaną, jednak nie wpisujesz do niej żadnych danych, nawet nie zerujesz zawartości tej zmiennej, a potem zapisujesz ją do pliku, stąd lądują do pliku randomowe śmieci; Jeśli chcesz zapisać zawartość faktury do pliku, to wykorzystaj przekazany argument wprow:faktura) w procedurze zapisz, a nie zmienną a, która jak widać do niczego w tym kodzie nie służy; W ogóle ten kod jest źle zaprojektowany - panuje w nim haos i ciężko wyczuć co w ogóle chcesz zrobić;

Jeśli chcesz zapisać wszystkie faktury to operuj na zmiennej a: t, którą masz zadeklarowaną globalnie - najlepiej to przekazuj ją w argumencie procedury zapisz i w pętli zapisuj po kolei każdy rekord do pliku tekstowego lub typowanego, albo całą tablicę jednorazowo procedurą BlockWrite jeśli chodzi o pliki amorficzne (lub jak wolisz także w pętli);

Taki niestety mam tok myślenia, a program to pokazuje najlepiej. Opiszę co mam zrobić. Tak już zdążyłeś zauważyć muszę zrobić fakturę, która zawiera imię, nazwisko, datę utworzenia faktury, nazwę artykułu, ilość tego artykułu, jego cenę. Mam zrobić ją dla maksymalnie 15 artykułów. Fakturę za pomocą procedury mam zapisywać do pliku i z tego pliku ją odczytać. Program powinien też mieć możliwość szukania po nazwisku faktur. Względnie mogę dać funkcję, która pozwoli na to aby tylko wczytywać dane z pliku, zapisywać nową fakturę lub nie robić nic (czyli wyłączyć program).

type
  Faktura = packed record
    Imie : String[15];
    Nazwisko : String[25];
    Age : Byte;
  end;
 
procedure Zapis(Sender: TObject);
var
  F: file of faktura;
  Rec : faktura;
begin

Write('Podaj imie: ');
readln(Rec.imie);
  
  AssignFile(F, 'dane.dat');
  try
    Rewrite(F);  // utworzenie pliku
    Write(F, Rec); // dodanie rekordu
  finally
    CloseFile(F);
  end;
end;

Tak to ma mniej więcej wyglądać? I potem w głównym programie odwołanie do tej procedury muszę zrobić w ten sposób?

begin
zapis(Sender: TObject);
end.
0

Ja bym zrobił coś takiego:

type
  TKlient = packed record
    Imie     : String[15];
    Nazwisko : String[25];
    Age      : Byte;
  end;

type
  TArtykul = packed record
    Nazwa : String[30];
    Ilosc : Word; // lub byte jeśli artykułów będzie zawsze mniej niż 255
    Cena  : Real;
end;

type
  TFaktura = packed record
    Klient  : TKlient;
    Artykul : Array[0..14] of TArtykul; // Tablica na 15 artykułów
    Data    : String[15] // ??
end;

procedure Zapis(fakt : TFaktura);
var
  F: file of TFaktura;
begin
  AssignFile(f, 'dane.dat');
  If not FileExists('dane.dat') then // Sprawdza czy plik dane.dat istnieje
  begin
    Rewrite(f);    // Jeśli nie to tworzy nowy
    Write(f, fakt);
  end;
  else
  begin  // Jeśli istnieje to dodaje dane na końcu.
    reset(f);           
    seek(FileSize(f)); 
 //    Nie jestem pewien ale te dwie linie chyba można zastąpić poleceniem append(f). A jeśli ani append ani ta konstrukcja nie działa to chyba by trzeba było napisać specjalną funkcję dopisującą rekord do pliku.
    Write(f, fakt);
  end;
  CloseFile(f);
end; 

Zmienną fakt dał bym globalną i uzupełniał za pomocą innych funkcji i procedur.

A w ogole bym to w klasę obudował :)

0
liberate1792 napisał(a)

Tak to ma mniej więcej wyglądać?

Mniej więcej tak, jednak najpierw uzupełnij rekord we wszystkie pola, jakie ma mieć faktura;

liberate1792 napisał(a)

I potem w głównym programie odwołanie do tej procedury muszę zrobić w ten sposób?

begin
zapis(Sender: TObject);
end.

Nie, Sender: TObject to argument wykorzystywany w zdarzeniach formularza/kontrolek w programowaniu obiektowym, które jak na razie nie powinno Ciebie interesować; Tworząc procedurę do zapisu faktury powinieneś w argumencie przekazać jako wartość właśnie fakturę, czyli rekord zawierający wszystkie informacje na temat danej faktury: klient, ilość artykułów i w ilu sztukach, cenę poszczególnych towarów oraz łączną kwotę, na jaką została wystawiona faktura - to takie podstawowe informacje (powinno być ich więcej, ale to tylko ćwiczenie jak sądzę);

Gdybyś korzystał z programowania obiektowego to można by elegancką klasę napisać, no ale...

0
program faktury;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TKlient = packed record
    Imie     : String[15];
    Nazwisko : String[25];
    Age      : Byte;
end;

type
  TArtykul = packed record
    Nazwa : String[30];
    Ilosc : Word; // lub byte jeśli artykułów będzie zawsze mniej niż 255
    Cena  : Real;
end;

type
  TFaktura = packed record
    Klient  : TKlient;
    Artykul : Array[0..14] of TArtykul; // Tablica na 15 artykułów
    Data    : String[15] // ??

end;
 
procedure Zapis(fakt : TFaktura);
var
  F: file of TFaktura;
begin
  AssignFile(f, 'dane.dat');
  If not FileExists('dane.dat') then // Sprawdza czy plik dane.dat istnieje
  begin
    Rewrite(f);    // Jeśli nie to tworzy nowy
    Write(f, fakt);
  end
  else
  begin  // Jeśli istnieje to dodaje dane na końcu.
    reset(f);
    seek(FileSize(f)); 
 //    Nie jestem pewien ale te dwie linie chyba można zastąpić poleceniem append(f). A jeśli ani append ani ta konstrukcja nie działa to chyba by trzeba było napisać specjalną funkcję dopisującą rekord do pliku.
    Write(f, fakt);
  end;
  CloseFile(f);
end;

procedure wprowadzanie1(wpis1:TFaktura);
begin
Write('Podaj imie: ');
      readln(wpis1.Imie);
Write('Podaj nazwisko: ');
      readln(wpis1.Nazwisko);
end;

procedure wprowadzanie2(wpis2:TArtykul);
        var liczba:integer;
        var a:integer;
begin
Write('Podaj liczbe pozycji : ');
readln(liczba);
for a:=1 to liczba do
      begin
Write('Podaj nazwe artykulu: ');
      readln(wpis2.nazwa);
Write('Podaj ilosc danego artykulu: ');
      readln(wpis2.ilosc);
Write('Podaj cene artykulu: ');
      readln(wpis2.cena);
      end;
end;
var i:integer;
var ile:integer;
var wpis1:TFaktura;
var fakt:TFaktura;
begin
writeln('Ile faktur? ');
readln(ile);
for i:=1 to ile do
begin
                   wprowadzanie1(wpis1);
end;
{writeln(' ');
for i:=1 to ile do
begin
                    wypisywanie(a[i]);

end;}
readln;
Zapis(fakt);
readln;
end.

Tak posiłkowałem się i to bardzo układem użytkownika babubabu. Teraz pytanie czy tak ten układ(lekko zmodyfikowałem dodając dwie procedury) może wyglądać?
Myślałem też nad tym by dać zmienna naleznosc, która by to określała kwotę, którą osoba musiałaby zapłacić. Chciałem zrobić z Ceny tablice by zapamiętywała ceny poszczególnych artykułów np:
-chleb sztuk: 1 cena: 2,50
-opakowanie masła sztuk: 2 cena: 6
należność: 2,50+6=8,50

Ach byłbym zapomniał wyskakuje błąd w poleceniu
seek(FileSize(f));
Nie pasują mu typy.

0
liberate1972 napisał(a)

Tak posiłkowałem się i to bardzo układem użytkownika babubabu. Teraz pytanie czy tak ten układ(lekko zmodyfikowałem dodając dwie procedury) może wyglądać?

Może wyglądać, choć zmieniłbym na pewno procedurę zapis:

procedure Zapis(fakt : TFaktura);
var
  F: file of TFaktura;
begin
  AssignFile(f, 'dane.dat');
  If not FileExists('dane.dat') then
  begin
    Rewrite(f);
    Write(f, fakt);
  end
  else
  begin
    reset(f);
    seek(FileSize(f)); // <-- nieprawidłowa ilość argumentów!!!
    Write(f, fakt);
  end;
  CloseFile(f);
end;

na prostszą (bez powtórzeń):

procedure Zapis(const Fakt: TFaktura);
var
  F: file of TFaktura;
begin
  AssignFile(F, 'dane.dat');

  try
    if FileExists('dane.dat') then
    begin
      Reset(F);
      Seek(F, FileSize(F)); // <-- tu prawidłowa ilość argumentów
    end
    else
      ReWrite(F);

    Write(F, Fakt);
  finally
    CloseFile(F);
  end;
end;

liberate1972 napisał(a)

Ach byłbym zapomniał wyskakuje błąd w poleceniu

seek(FileSize(f)); 

Nie pasują mu typy.

A zastanowiłeś się dlaczego mu nie pasują? Widziałeś deklarację procedury Seek? :

procedure Seek(var F; N: Longint);

Widzisz tutaj dwa argumenty? W Twoim kodzie nie podajesz jako pierwszego argumentu zmiennej plikowej, stąd masz błąd niezgodności typów;

0
 
function wprowadzKlienta : TKlient;
var
  tmpResult : TKlient;
begin
  Write('Podaj imie: ');
  readln(tmpResult.Imie);
  Write('Podaj nazwisko: ');
  readln(tmpResult.Nazwisko);
  Write('Podaj wiek: ');
  readln(tmpResult.Age);
  result := tmpResult;
end;
 
function wprowadzArtykul : TArtykul
var
  tmpResult : TArtykul;
begin
  Write('Podaj Nazwe: ');
  readln(tmpResult.Nazwa);
  Write('Podaj Ilosc: ');
  readln(tmpResult.Ilosc);
  write('podaj cene: ');
  readln(tmpResult.Cena);
  result := tmpResult;
end;

function wystawfakture : TFaktura;
var
  max,i : Integer;
  tmpResult : TFaktura;
begin
  tmpResult.Klient := wprowadzKlienta;
  Write('Podaj date: ');
  readln(tmpResult.Data);
  repeat
    Write('Podaj ilosc artykolow (Nie wieksza niz 15 nie mniejsza niż 1): ');
    Readln(max);
  until (max in [1..15]);  // <- Zabezpieczenie by nie przekroczyć zakresu tablicy. Wielu zabezpieczeń przed idiotami brakuje ale pisane na szybo :P
  for i := 0 to max - 1 do
    tmpResult.Artykul[i] := wprowadzartykul;
  result := tmpResult;
end;

begin
  zapis(wystawFakture);
end;

Kod nie jest idealny i może zawierać błędy ale mniej więcej tak to widzę :D. Dzięki podziałowi na funkcje i procedury i przeniesienie ich do oddzielnego unitu kod głównego programu może zawierać jedną linijkę (sam zapis faktur do pliku). Dodać do tego jakieś proste menu, odczyt, sortowanie, wyświetlanie i program gotowy :)

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