Kirjautuminen

Haku

Tehtävät

Opasarkisto: Pascal-ohjelmointi: Osa 4 - Tiedostot

  1. Osa 1 - Mistä Pascal alkaa?
  2. Osa 2 - Vakiot, muuttujat ja tietueet
  3. Osa 3 - Silmukat ja ehtolauseet
  4. Osa 4 - Tiedostot
  5. Osa 5 - Funktiot, aliohjelmat ja omat moduulit

Kirjoittaja: Metabolix (2004).

⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠


Tiedostot ovat ennemmin tai myöhemmin miltei väistämätön osa ohjelmointia. Niiden käyttö on siis syytä opetella hyvin, jotta siitä tulee rutiinia eikä siihen tarvitse sen enempää keskittyä enää myöhemmin.

Alustus

Myös tiedostoja käytetään muuttujien avulla. Muuttuja on tekstitiedoston tapauksessa tyyppiä TextFile ja muiden tiedostojen tapauksessa File. Tyyppiä File voi tarkentaa määrittelemällä, mitä tiedosto sisältää. Esimerkiksi File of Longint sisältäisi 32-bittisiä kokonaislukuja. Jos tyyppiä ei määritellä, puhutaan tyypittömästä tiedostosta.

Ensimmäinen asia, joka tälle muuttujalle täytyy tehdä ennen kuin tiedostoa voi käyttää, tapahtuu funktiolla AssignFile, joka on joissakin kääntäjissä nimeltään vain Assign. Kyseinen funktio muuttaa ulkoisen tiedostonimen sisäiseksi tiedostonimeksi. Käytännössä tämä tarkoittaa, että se, mikä tehdään tälle muuttujalle, tehdäänkin itse asiassa kyseiselle tiedostolle.

Seuraavaksi tulee päättää, mitä tiedostolla aiotaan tehdä. Jos tiedostosta halutaan lukea, se tulee avata funktiolla Reset. Koko tiedoston saa tyhjennettyä uudelleenkirjoitusta varten funktiolla Rewrite. Tekstitiedostoja käsiteltäessä Append avaa tiedoston niin, että kirjoittamista jatketaan sen lopusta. Tyypittömälle tiedostolle voidaan funktioiden Reset ja Rewrite yhteydessä asettaa tiedostosta luettavien tietueiden koko tavuina. Jos kokoa ei määritellä, se on historiallisista syistä 128 tavua.

Lopuksi tiedosto suljetaan funktiolla CloseFile, joka on joissakin kääntäjissä nimeltään lyhyemmin Close.

Kattavan luettelon tiedostonkäsittelyn funktioista löydät Pascal-hakemistosta.

Tekstitiedostot ja konsoli

Tekstitiedostoista ja konsolista luetaan samalla tavalla. Merkittävin ero on se, että konsolista luettaessa lukeminen tapahtuu vasta Enteriä painettaessa. Kun halutaan lukea konsolista, lukufunktiosta jätetään määrittelemättä tiedosto, ja vastaavasti kun halutaan kirjoittaa konsoliin, kirjoitusfunktiosta jätetään määrittelemättä tiedosto.

Tekstitiedostoista ja konsolista voidaan lukea kahta erilaista tietoa: tekstiä tai lukuja. Luvutkin luetaan tekstimuodossa, mutta ne muutetaan automaattisesti sopiviksi. Vastaavasti kirjoitettaessa luvut muutetaan automaattisesti tekstiksi. Kuusitoistajärjestelmän (heksadesimaali-) luvut tunnistaa dollarimerkistä ($12345), desimaalierottimena toimii piste ja kymmenpotenssimuoto merkitään kirjaimella 'e' tai 'E' (esimerkiksi 1.342e-6 tarkoittaa 1.342 * 10-6). Mikäli teksti, jota yritetään muuttaa luvuksi, sisältää muita kuin edellä mainittuja merkkejä tai numeroita, tapahtuu virhe.

Lukeminen tapahtuu joko Read- tai Readln-funktiolla. Erona on se, että Readln siirtyy lopuksi seuraavalle riville. Konsolista luettaessa on yleensä syytä käyttää Readln-funktiota, koska kun painetaan Enteriä, seuraava Readln-funktio huomaa rivinvaihdon ja olettaa, että rivi oli sitä varten. Mikäli konsolin lukemisen haluaa aivan välttämättä suorittaa pelkällä Read-funktiolla, on sen kanssa syytä noudattaa suurta varovaisuutta. Muuttuja, johon luettava arvo asetetaan, voi olla tyypiltään kokonaisluku, liukuluku tai merkkijono. Peräkkäiset luvut erotellaan tekstissä väleillä. Merkkijonoon luettaessa kaikki rivin merkit luetaan kerralla väleistä riippumatta.

Kirjoittaminen tapahtuu joko Write- tai Writeln-funktiolla. Erona on se, että Writeln kirjoittaa lopuksi rivinvaihtomerkinnän. Muuttuja, joka korjoitetaan, voi olla tyypiltään kokonaisluku, liukuluku tai merkkijono. Peräkkäisten lukujen väliin ei laiteta automaattisesti väliä, vaan se täytyy merkitä itse. Sekä lukiessa että kirjoittaessa muuttujia voidaan laittaa peräkkäin niin monta kuin halutaan.

Kirjoitettaessa arvoille voidaan haluttaessa määrätä vähimmäispituus, eli se, montako merkkiä vähintään kirjoitetaan. Tämä tapahtuu kirjoittamalla muuttujan perään kaksoispiste (:) ja haluttu vähimmäispituus. Mikäli kirjoitettava asia veisi vähemmän tilaa, ennen sitä tulee tarvittava määrä tyhjää tilaa. Tällä tavalla esimerkiksi eri kokoisia lukuja saadaan kirjoitettua tietyn levyisiksi sarakkeiksi. Liukuluvuille näitä pituuksia voi antaa kaksi: ensin koko luvun pituuden ja sitten desimaaliosan pituuden, jolloin luku pyöristetään tähän tarkkuuteen. Jos kuitenkin kirjoitat vain yhden mitan, luku kirjoitetaan vähintään sen mittaisena kymmenpotenssimuodossa. Ilman yhtäkään määrettä liukuluku kirjoitetaan kymmenpotenssimuodossa koko tarkkuudellaan.

program Esimerkki;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  Ulkofile: String;
  Sisafile: TextFile;

  Liukuluku: Single;

  Apu: Integer;

begin
  (* Pyydetään käyttäjältä olemassaolevan tiedoston nimi
   * Tämä tulostuu ruudulle, koska tiedostoa ei määritellä *)
  Writeln('Kirjoita olemassaolevan tiedoston nimi!');

  repeat begin
    (* Luetaan se muuttujaan Ulkofile *)
    Readln(Ulkofile);

    (* Jos tiedosto on olemassa, poistutaan silmukasta Break-käskyllä *)
    if FileExists(Ulkofile) then Break;

    (* Tänne päästiin jos se ei ole olemassa. Pyydetään siis uusi *)
    Writeln('Huijasit! Ei tuollaista tiedostoa ole olemassakaan!');
    Writeln('Anna uusi nimi');

    (* Koska False on yhä epätosi, palataan silmukan alkuun *)
  end until False;

  (* Liitetään Sisafile Ulkofileeseen *)
  AssignFile(Sisafile, Ulkofile);

  (* Tyhjennetään file ja ilmoitetaan myös käyttäjälle *)
  Rewrite(Sisafile);
  Writeln('Hoh hoh hah hah haa! Söinpäs sisäfileen!');

  (* Toistetaan seuraava 20 kertaa *)
  for Apu := 1 to 20 do
  begin
    (* Kirjoitetaan kaksi sattumanvaraista lukua (0 .. 99) ja
     * niiden väliin yksi väli. Loppuun tulee rivinvaihto.
     * Jotta luvut näkyisivät siististi, määrätään ensimmäiselle
     * leveydeksi vähintään kolme merkkiä. *)
    Writeln(Sisafile, Random(100) : 3, ' ', Random(100));
  end;

  (* Suljetaan Sisafile ja avataan se uudestaan lukemista varten *)
  CloseFile(Sisafile);
  Reset(Sisafile);

  (* Toistetaan, kunnes ollaan tiedoston lopussa *)
  while not Eof(Sisafile) do
  begin
    (* Toistetaan, kunnes ollaan rivin lopussa *)
    while not Eoln(Sisafile) do
    begin
      (* Luetaan muuttuja kerrallaan *)
      Read(Sisafile, Liukuluku);

      (* Kirjoitetaan ruudulle ja laitetaan loppuun väli.
       * Muuttuja on liukuluku, joten se kirjoitetaan ruudulle
       * kymmenpotenssimuodossa. Määrätään kokonaispituudeksi
       * vähintään 7. Tähän sisältyy koko luku ja tarvittaessa
       * edeltävät välit. Desimaaleja tulostettakoon kaksi. *)
      Write(Liukuluku : 7 : 2, ' ');
    end;

    (* Siirrytään seuraavalle riville sekä tiedostossa että ruudulla *)
    Readln(Sisafile);
    Writeln;
  end;

  (* Suljetaan Sisafile *)
  CloseFile(Sisafile);

  (* Odotetaan Enteriä ennen kuin suljetaan ohjelma *)
  Writeln('Paina Enter, niin ohjelma sulkeutuu.');
  Readln;
end.

Muut tiedostot

Tiedostosta voi lukea mihin tahansa muuttujaan. Kaikki muuttujat ovat tyypiltään lukuja tavalla tai toisella. Jopa teksti on vain joukko lukuja, joista jokainen tarkoittaa tiettyä merkkiä. Kun kyseessä ei ole tekstitiedosto, eivät luvutkaan ole tiedostossa tekstinä. Esimerkiksi luku 443295962 tallentuisi tiedostoon neljänä peräkkäisenä tavuna. Kyseinen luku näyttää kuusitoistajärjestelmässä tältä: $1A6C28DA. Tämän voimme jakaa kätevästi neljään tavun kokoiseen osaan: $1A $6C $28 $DA. Nämä osat löytyvät tiedostosta käänteisessä järjestyksessä: $DA $28 $6C $1A. Onneksi tästä ei käytännössä tarvitse välittää kuin poikkeustapauksissa.

Muut kuin tekstitiedostot voidaan avata sekä Reset- että Rewrite-funktiolla. Kummassakin tapauksessa niistä voi lukea ja niihin voi kirjoittaa. Erona on se, että Rewrite tyhjentää tiedoston, jolloin lukeminen käy mahdottomaksi. Reset-funktiolla avattuun tiedostoon kirjoitettaessa tiedoston entinen sisältö korvautuu sitä mukaa, kun tiedostoon kirjoitetaan. Tiedon lisääminen tiedoston alkuun tai keskelle vaatii väliaikaistiedostojen tai -muuttujien käyttöä.

Tyypittömän tiedoston lukeminen ja kirjoittaminen tapahtuu muista poiketen funktioilla BlockRead ja BlockWrite. Näille annetaan parametreinä tiedosto, kohdemuuttuja ja tietueiden määrä sekä haluttaessa myös muuttuja, johon merkitään luettujen tai kirjoitettujen tietueiden määrä mikäli vaikkapa tiedosto loppuu kesken. Tietueen koko määritellään tiedoston avaamisen yhteydessä Rewrite- tai Reset-funktion toisena parametrinä.

program MuutTiedostot;

{$APPTYPE CONSOLE}

(* Määritellään kaikki tarvittavat tyypit *)
type
  TPossu = record
    Pituus, Leveys, Korkeus, Ika, Paino, Rasvaprosentti: Single;
    Lemu: Integer;
  end;
  (* Tiedostotyyppejä voi määritellä valmiiksi *)
  TPorsaanfile = File of TPossu;

var
  Porsaanfile: TPorsaanfile;

  Possut: Array [1 .. 10] of TPossu;
  Numero: Integer;

  Tyypit_On: File;
  Palanen: Byte;

begin
  (* Ostetaan ja lihotetaan possuja *)
  OstaPossuja(@Possut, 10, Halvalla);
  Lihota(@Possut, 10, Iso_Kuin_Ahtisaari);

  (* Avataan 'Possut.röh' Porsaanfileeseen *)
  AssignFile(Porsaanfile, 'Possut.röh');
  Rewrite(Porsaanfile);

  (* Kirjoitetaan possut yksitellen ja suljetaan Porsaanfile *)
  for Numero := 1 to 10 do
    Write(Porsaanfile, Possut[Numero]);
  CloseFile(Porsaanfile);

  (* Avataan possut tyypittömään tiedostoon *)
  AssignFile(Tyypit_On, 'Possut.röh');

  (* Siirrytään alkuun ja asetetaan tietueen kooksi yksi tavu *)
  Reset(Tyypit_On, 1);

  (* Luetaan possut tavun palasina ja siirretään palaset näkyville *)
  while not Eof(Tyypit_On) do begin

    (* Luetaan yhden palan verran muuttujaan Palanen *)
    BlockRead(Tyypit_On, Palanen, 1);

    (* Koska Palanen on tyyppiä Byte, voimme kirjoittaa sen ruudulle *)
    Write(Palanen);
  end;
  (* Suljetaan Tyypit_On *)
  CloseFile(Tyypit_On);
end.

Lauri Kenttä, 15.9.2004


Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta