25.Prednaska/Cvicenie0

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

25. Cvičenie


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


Rozcvička

1. kopírovať textový súbor cisla.txt do cisla1.txt

  • kde vstupný súbor obsahuje v každom riadku jedno celé číslo a výstupný súbor bude obsahovať všetky čísla zo vstupu okrem posledného
  • nepoužívajte polia ani reťazce


2. textový súbor cisla.txt obsahuje len celé čísla, pričom v niektorých riadkoch ich môže byť aj niekoľko, alebo niektoré riadky môžu byť aj prázdne

  • prečítať súbor a vypísať poradové číslo riadku, v ktorom je najväčší súčet čísel a vypísať aj tento súčet
  • nepoužívajte polia ani reťazce


3. prečítajte textový súbor subor.txt a vypíšte počet prázdnych riadkov v tomto súbore

  • nepoužívajte reťazce


Cvičenie

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

  • meno inštancie môžete zvoliť ľubovoľné, napr. Subor, Data, Stream, FileStream, F, Dada, Prud, ...
var
  F: TFileStream;
begin
  F := TFileStream.Create('file.dat', fmCreate);
  F.Free;
  WriteLn('done');
  ReadLn;
end.
  • 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;
  • v prieskumníkovi vidíme, že súbor má presne 256 bajtov
  • môžeme skontrolovať obsah v PSPad - v hexeditore, resp. na tabuľu naznačiť prvých niekoľko bajtov súboru


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

var
  F: TFileStream;
  W: Word;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for W := 0 to 255 do
    F.WriteBuffer(W, SizeOf(Word));
  F.Free;
  • v prieskumníkovi vidíme, že súbor má presne 512 bajtov
  • môžeme skontrolovať obsah v PSPad - v hexeditore


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

var
  F: TFileStream;
  I: Integer;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for I := 0 to 255 do
    F.WriteBuffer(I, SizeOf(Integer));
  F.Free;
  • v prieskumníkovi vidíme, že súbor má presne 1024 bajtov
  • môžeme skontrolovať obsah v PSPad - v hexeditore


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

var
  F: TFileStream;
  I, N: Integer;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for I := 0 to 255 do
  begin
    F.ReadBuffer(N, SizeOf(Integer));   // tu sa nesmie čítať do I
    Write(N, ' ');
  end;
  F.Free;


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;
  • 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;
  • 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)
var
  F: TFileStream;
  I: Integer;
  R: Real;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for I := 0 to 255 do
  begin
    R := I;
    F.WriteBuffer(R, SizeOf(Real));
  end;
 
  F.Position := 0;
  while F.Position < F.Size do
  begin
    F.ReadBuffer(R, SizeOf(Real));
    Write(R:0:2, ' ');
  end;
  F.Free;
  • 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:

var
  F: TFileStream;
  I: Integer;
  R: Real;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  for I := 0 to 255 do
  begin
    F.WriteBuffer(I, SizeOf(Integer));
    R := I;
    F.WriteBuffer(R, SizeOf(Real));
  end;
 
  F.Position := 0;
  while F.Position < F.Size do
  begin
    F.ReadBuffer(I, SizeOf(Integer));
    F.ReadBuffer(R, SizeOf(Real));
    Write(I, ' ', R:0:2, ' ');
  end;
  F.Free;
  • 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)

var
  F: TFileStream;
  I, Index: Integer;
  R: Real;
begin
  F := TFileStream.Create('file.dat', fmOpenReadWrite);
  repeat
    Write('? ');
    ReadLn(Index);
    F.Position := Index * (SizeOf(Integer) + SizeOf(Real));
    F.ReadBuffer(I, SizeOf(Integer));
    F.ReadBuffer(R, SizeOf(Real));
    WriteLn(I, ' ', R:0:2, ' ');
  until Index = 0;
  F.Free;
  • prípadne vyskúšať bez násobenia v priradení do Position


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 jednopduchš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

var
  F: TFileStream;
  Pole: array of Integer;
  I: Integer;
begin
  SetLength(Pole, 100);
  for I := 0 to High(Pole) do
    Pole[I] := Sqr(I + 1);
  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)