25.Prednaska/Cvicenie

Z Pascal
Prejsť na: navigácia, hľadanie

25. Cvičenie


< 25.Prednáška | riešené úlohy


Cvičenie

1. zadeklarovať údajový prúd ako objekt TFileStream (pozor, je to trieda), vytvoriť inštanciu (vytvoriť nový súbor) a hneď zatvoriť

  • vznikne prázdny súbor - dá sa skontrolovať v prieskumníkovi


2. metódy WriteBuffer a ReadBuffer zapisujú a čítajú zo súboru - prvý parameter musí byť premenná

  • do súboru zapísať 256 bajtov od 0 do 255
var
  F: TFileStream;
  B: Byte;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite); // môže tu byť namiesto fmCreate, lebo súbor už existuje
  for B := 0 to 255 do
    F.WriteBuffer(B, SizeOf(Byte));
  F.Free;
end;
  • v prieskumníkovi vidíme, že súbor má presne 256 bajtov


3. to isté, ale zapisujeme Word - po 2 bajty

  • v prieskumníkovi vidíme, že súbor má presne 512 bajtov
F.WriteBuffer(W, SizeOf(Word));


4. to isté, ale zapisujeme Integer - po 4 bajty

  • v prieskumníkovi vidíme, že súbor má presne 1024 bajtov
F.WriteBuffer(I, SizeOf(Integer));


5. vypísať tento súbor - v cykle čítať celé čísla


6. čo sa stane, keď pred for-cyklus príde priradenie do Position a cyklus len do 254:

var
  F: TFileStream;
  I, N: Integer;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  F.Position := 4;
  for I := 0 to 254 do
  begin
    F.ReadBuffer(N, SizeOf(Integer));
    Write(N, ' ');
  end;
  F.Free;
end;
  • môže sa vyskúšať nemeniť hornú hranicu cyklu - program spadne
  • začne sa vypisovať až od 4. bajtu, teda prvé celé číslo sa prekočí:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ...


7. to isté, ale Position := 1

  • vypíše sa 255 divných čísel:
16777216 33554432 50331648 67108864 83886080 100663296 117440512 134217728 15099
4944 167772160 184549376 201326592 218103808 234881024 251658240 268435456 28521
2672 301989888 318767104 335544320 352321536 369098752 385875968 402653184 41943 ...
  • uvažovať o tom, čo sa stalo - pomôže pozrieť v hex-editore
  • môžeme výpis nie desiatkovo ale 16-ovo (treba SysUtils do uses):
var
  F: TFileStream;
  I, N: Integer;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  F.Position := 1;
  for I := 0 to 254 do
  begin
    F.ReadBuffer(IntToHex(N, 8), SizeOf(Integer));
    Write(N, ' ');
  end;
  F.Free;
end;
  • teraz výpis
01000000 02000000 03000000 04000000 05000000 06000000 07000000 08000000 09000000
 0A000000 0B000000 0C000000 0D000000 0E000000 0F000000 10000000 11000000 1200000
0 13000000 14000000 15000000 16000000 17000000 18000000 19000000 1A000000 1B0000 ...
  • prípadne porovnať s takýmto 16-ovým výpisom aj pre Position := 4, keď to bolo ešte dobre:
00000001 00000002 00000003 00000004 00000005 00000006 00000007 00000008 00000009
 0000000A 0000000B 0000000C 0000000D 0000000E 0000000F 00000010 00000011 0000001
2 00000013 00000014 00000015 00000016 00000017 00000018 00000019 0000001A 000000 ...


8. zapísať a potom aj vypísať 256 reálnych čísel - pozrieť v hex-editore - zistiť veľkosť súboru

  • dve vlastnosti Position a Size môžeme použiť na otestovanie konca súboru (nemáme EOF)
  • namiesto for-cyklu pri čítaní while (kým nie je koniec súboru)
  • výpis
0.00 1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00 11.00 12.00 13.00 14.00
15.00 16.00 17.00 18.00 19.00 20.00 21.00 22.00 23.00 24.00 25.00 26.00 27.00 28 ...
  • vyskúšať čítať tento súbor a vypisovať ako Integer (prípadne Byte alebo Word)


9. do súboru zapisovať dvojice: celé číslo od 0..255 a realne číslo s tou istou hodnotou:

  • tento súbor obsahuje 512 čísel pričom sa striedajú Integer a Real
  • pozrieť aj v hex-editore
  • uvedomiť si, že keby nám neprezradili, čo a ako je v ňom uložené, ťažšie sa to zistí, ťažšie sa zistí, či to čo čítame (napr. najprv Real a potom Integer) je zlý výsledok


10. vieme vypísať všetkých 256 dvojíc čísel, teraz chceme iba jednu dvojicu, poradové číslo zadané zo vstupu (priamy prístup)

...
F.Position := Index * (SizeOf(Integer) + SizeOf(Real));
F.ReadBuffer(I, SizeOf(Integer));
F.ReadBuffer(R, SizeOf(Real));
...

11. do súboru dáme 256 rôznych znakov (#0..#255)

var
  F: TFileStream;
  C: Char;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for C := #0 to #255 do
    F.WriteBuffer(C, SizeOf(Char));
  F.Free;
  • keď pozrieme v hex-editore, prvých 256 bajtov je rovnakých, ako keď sme zaposovali Byte 0..255
  • ďalej nasleduje skoro 3 kilo bajty smetí, ktoré tam ostali z predchádzajúceho príkladu
  • niekoľko možností:
  • do Create dať fmCreate
  • pred for-cyklu dať
      F.Size := 0;
  • za for-cyklus dať
      F.Size := F.Position;


12. ďalej sa bude pracovať so statickým poľom celých čísel

  • zaplniť pole druhými mocninami
  • naraz celé zapísať
  • po jednom vypisovať
var
  F: TFileStream;
  Pole: array [1..100] of Integer;
  I: Integer;
begin
  for I := 1 to High(Pole) do
    Pole[I] := I * I;
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  F.WriteBuffer(Pole, SizeOf(Pole));
 
  // F.Position := 0;
  while F.Position < F.Size do
  begin
    F.ReadBuffer(I, SizeOf(Integer));
    Write(I, ' ');
  end;
  F.Free;
  • najprv vyskúšať bez Position := 0;
  • while-cyklus jednoduchšie pomocou funkcie ReadDWord
  while F.Position < F.Size do
    Write(F.ReadDWord, ' ');


13. zapísať najprv druhú polovicu poľa (od 51..100) a potom prvú (od 1..50), potom vypíšeme

  ...
  F.WriteBuffer(Pole[51], 50 * SizeOf(Integer));
  F.WriteBuffer(Pole[1], 50 * SizeOf(Integer));
  ...  


14. to isté cez dynamické pole

  ...
  F := TFileStream.Create('file.dat', fmCreate);
  F.WriteBuffer(Pole, SizeOf(Pole));
  F.Free;
  ...
  • toto je chybné riešenie - pozrite v hex-editore: zapísali sa 4 bajty a nie 400
  • pre dynamické pole premenná Pole je vlastne smerníkom do dynamickej pamäte a preto SizeOf(Pole) je 4
  • správne má byť
  F.WriteBuffer(Pole[0], Length(Pole) * SizeOf(Integer));


15. pre daný binárny súbor celých čísel vytvoriť dynamické pole - podľa veľkosti súboru vytvor a prečítaj dynamické pole

var
  F: TFileStream;
  Pole: array of Integer;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  SetLength(Pole, F.Size div SizeOf(Integer));
  if Pole <> nil then
    F.ReadBuffer(Pole[0], Length(Pole) * SizeOf(Integer));
  • ak je F.Size deliteľné 4, mohli by sme ReadBuffer zapísať aj takto
    F.ReadBuffer(Pole[0], F.Size);


Domáca úloha

1. napíšte program, ktorý vytvorí binárny súbor z riadkov textového súboru

  • textový súbor studenti.txt obsahuje riadky tvaru
meno;rocnik priemer
  • treba to prečítať do záznamu:
type
  TStudent = record
    Meno: string[15];
    Rocnik: Byte;
    Priemer: Real;
  end;
  • každý prečítaný záznam sa zapíše do súboru
  • v hex-editore sa pozrite, ako je to uložené, koľko bajtov zaberá jeden záznam (SizeOf(TStudent))
  • NDÚ odovzdávať len text projektu (napr. project1.lpr)