Eljárásai: SIO.GetInt, SIO.PutInt, SIO.GetChar, SIO.PutChar, SIO.GetReal(honnan), SIO.PutReal(mit, hova), SIO.LookAhead: előreolvasás.
A Modula-3 önmagában nem biztosít lehetőséget a fájlkezelésre. A legtöbb programnyelvhez hasonlóan, ez nem azt jelenti, hogy közvetlenül az operációs rendszerrel kell kommunikálnunk: a Modula-3 nyelvi környezete biztosítja azokat az objektumokat és eljárásokat amelyek kezelik az operációs rendszer felé történő hívásokat.
A Modula-3 nyelvi környezete input és output adatfolyamokat biztosit fájlok hozzáféréséhez. Ezek a nyelv standart könyvtárában vannak definiálva, reader és writer néven. Ezek olyan objektumok, melyeket összekapcsolhatunk egy fájllal az inicializáció során. Arra is van lehetőség, hogy egy output adatfolyamot a monitorhoz vagy a nyomtatóhoz társítsuk vagy egy input adatfolyamot egy input eszközzel mint például a billentyűzet.
Tegyük fel, hogy a háttértároló tartalmaz egy input.dat nevű fájlt. A következő programrészlet társítja az input adatfolyamot a fájllal:MODULE ReadFile EXPORTS Main; IMPORT Rd, FileRd, SIO, SF; CONST FileName = "input.dat"; VAR rd: Rd.T; t: TEXT; IF SF.FileExists(FileName) THEN rd:= FileRd.Open(FileName); (*kapcsolatot epit fel egy fajllal *) WHILE NOT Rd.EOF(rd) DO (*fajl vege ellenorzes*) t:= Rd.GetLine(rd); (*olvasás a sorvegeig *) SIO.PutText(t); SIO.NIQ; END; Rd.Close(rd) (*fajl bezarasa*) END (*IF*) END ReadFile.
rd az az objektum , amely az input adatfolyamot reprezentálja. A FileRd.Open eljárás inicializálja az input adatfolyam és társítja azt a fájllal. Az rd-t mint egy a fájlra mutatót pointert használjuk. A fájlból olvasást a következőképpen végezhetjük el.VAR rd: Rd.T; BEGIN rd= FileRd.Open("input.dat");
vagyt:= Rd.GetLine(rd);
A GetLine parancs a következő sorvége karakterig olvas a fájlból és az adatot hozzárendeli a t TEXT típusú változóhoz. A GetChar parancs egyetlen karaktert olvas ki a fájlból. A következő programrészlet teszteli. Hogy elértük-e a fájl végét:c:= Rd.GetChar(rd);
A fájlból olvasás majdnem mindig egy WHILE ciklussal történik.Rd.EOF(rd) MODULE WriteFile EXPORTS Main; IMPORT Wr, FileWr; CONST FileName="output.dat"; VAR wr: Wr.T; (*iro objektumt*) BEGIN wr:=FileWr.Open(FileName); (*kapcsolatot epit fel egy fajllal *) Wr.PutText(wr, "first line\n"); (*kimenet fajlba *) Wr.PutText(wr, "2\n"); Wr.PutText(wr, "--End--\n"); Wr.Close(wr) (* bezarja a fajlt *) END WriteFile.
Mielőtt elkezdenénk olvasni egy fájlt általában szükséges megvizsgálni, hogy hozzáférhető-e, az SF.FileExits függvényt használja erre. A függvény visszatérési értéke true lesz ha a fájl olvasható. Az SF (simple file) modul tartalmaz olyan hasznos utility függvényeket, amelyek egyszerűbbé teszik a gyakran használt fájlkezelő funkciókat mint a rugalmasabb de sokkal komplikáltabb könyvtári függvények
A fájl írás ezzel analóg módon történik: társítunk egy output adatfolyamot egy a háttértárolón
lévő fájllal. Ha a fájl még nem létezik automatikusan létrejön. Ha létezik már ilyen nevű
fájl akkor az újonnan létrehozott fájl felülírja a régit és annak tartalma elveszik. A
WrPutText vagy a Wr.PutChar eljárásokkal írhatunk fájlba.
Ezek absztrakt modulok annyiban, hogy csak a bemeneti és kimeneti adatfolyamok viselkedését
definiálják. Ezeknek a moduloknak az eljárásai olyan metódusokat hívnak meg, amelyekkel az
összes bemeneti vagy kimeneti adatfolyamnak rendelkeznie kell. Az Rd.T és Wr.T objektumok
ezeket a metódusokat, csak mint üres vázakat tartalmazzák. Az Rd.T és Wr.T altípusok
implementálóinak a feladata , hogy életet leheljenek ezekbe a metódusokba. A FileRd és FileWr
modulok ilyen altípusokat implementálnak. Úgy viselkednek mint az Rd.T vagy Wr.T , és
birtokolják az összes szükséges metódust fájlok olvasásához és írásához az operációs rendszer
szolgáltatásain keresztül. Ily módon a Modula-3 könyvtár meghatároz egy fogalmat fizikai
közegek olvasására és írására és biztosítja az egységességet. Hasonló képen írhatunk a
képernyőre és a nyomtatóra vagy fájlokba. Még a programok közötti kommunikáció is lehetséges
speciális input és output adatfolyamokkal.(adatfolyamokat csatornákhoz köthetünk. Az alábbi
táblázat néhány input/output eszköz nevét mutatja, a megfelelő input és output adatfolyam
objektumokat implementáló modulokkal együtt
Fájl írás/olvasás | FileRd/FileWr |
Képernyőre írás | Stdio: output adatfolyam stdout |
Billentyűzetről olvasás | Stdio: input adatfolyam stdin |
Nyomtatóra írás | Operációs rendszer függő; általában FileWr-en keresztűl speciális fájlnévvel |
A Seek eljárás lehetőséget nyújt egy a háttértárolón lévő megnyitott fájlban az írási, olvasási pozíció megváltoztatására. Nem minden adatfolyam bír a Véletlenszerű hozzáférés tulajdonsággal. ( a billentyűzet és a képernyő nem ilyenek) A tulajdonság meglétének ellenőrzése a Seekable függvénnyel lehetséges. Az aktuális pozíciót az Index adja vissza.
Néhány input adatfolyam nem képes folyamatosan új adatot biztosítani (bár még nem értünk az adatfolyam végére); az Rd.GetChar meghívása megszakításos bemeneti adatfolyam esetén blokkolja a programot, amíg új adatok lesznek elérhetőek. A billentyűzetet is ilyen adatfolyam: amíg a felhasználó nem visz be adatot a program várakozik. Ezt az attribútum ellenőrizhető a Rd.Intermitt függvénnyel.
Sok esetben az adatok nem íródnak ki azonnal egy output adatfolyamra annak érdekében, hogy az átviteli sebességet javítsák. merevlemezre való írás például majdnem ugyanannyi ideig tart egy teljes adatblokk esetén, mint egyetlen bájt esetén. Emiatt az adatokat a főmemóriában tároljuk egy pufferben és akkor írjuk ki őket ténylegesen amikor kitesznek egy teljes blokkot. A merevlemez tipikus blokkméretei a következők:512, 1024, 4096 bájt. Ez azt jelenti, hogy figyelnünk kell arra, hogy a program ne termináljon ha még adat van a pufferben. Wr.Flush explicit módon kiírja a puffer tartalmát, mielőtt az betelne, így módon az adatok folyamatosságát biztosíthatjuk.. Azt hogy van-e puffer a program és az output adatfolyam között a Wr.Buffer függvénnyel ellenőrizhetjük. Nem pufferelt output adatfolyam esetén minden egyes írás funkció hívásakor a hívó programnak addig kell várnia, amíg az adat fizikailag nem tárolódik. Az input adatfolyamoknak mindig puffereltnek kell lennie, mivel az adatok az eszköz sebességével (vagy a felhasználó gépelési sebességével jönnek) ami gyorsabb lehet, mint amit a program el tud olvasni. Az input puffer ciklikus listaként funkcionál: ha a program gyorsabb, mint a beviteli eszköz (vagyis a puffer üres), akkor a program várakozik. Ha a beviteli eszköz a gyorsabb akkor az adatot összegyűjti a puffer. Ha a puffer betelik akkor a beviteli eszköz kénytelen várakozni.
PROCEDURE PutRealArray(wr: Wr.T; READONLY r: ARRAY OF REAL)= BEGIN FOR i:= FIRST(r) TO LAST(r) DO Wr.PutText(wr, Fmt.lnt(i) & "" & Fmt.Real(r[ij) & "\n"); (*index ertek *) END; (*FOR*) END PutRealArray;
Mind az Rd és a Wr csak olyan eljárásokat tartalmaz, amelyek segítségével karaktereket lehet írni és olvasni. (a TEXT típus egy karakter sorozat). Ezek a modulok csak nyers adatot átvitelét képesek kezelni Ahhoz, hogy számokat vagy Boolean típusokat tudjunk tárolni, először formázni kell azokat; vagyis ahhoz hogy olyan formára alakítsuk őket, amit a Wr fel tud dolgozni, át kell alakítani az értékeket a nekik megfelelő TEXT reprezentációra. Például ha egy Boolean értéke true akkor a text reprezentációja "TRUE" lesz. Ellenkező irányban, az olvasásnak vissza kell konvertálnia a szöveget annak az eredeti típusára. Úgy mondjuk, hogy letapogatjuk a szöveget, hogy megszerezzük az adatokat. Szöveg fájlok használata több tárhelyet igényel a fájlhoz, de meg van az előnye, hogy a fájl tartalma olvasható. Az Fmt és Scan modulok az alaptípusokat konvertálják TEXT típusra és vice versa. Az eljárás ezért azt a tényt használja ki, hogy az indexeket és érékeket a következő képen tároljuk:
Az eljárás a következő sorvége jelig (EOL) olvas aztán átadja az adatot a t TEXT típusú változónak.index blank value EOL
Ezután megkeresi a szóközt, amely elválasztja az indexet az értéktől, majd átalakítja t első részét integerré a maradékot, pedig valós számmá. A Text.FindChar(t,c) eljárás megkeresi a t TEXT típusú változóban az első c karaktert és annak pozíciójával tér vissza. Ha t nem tartalmaz ilyen karaktert az eljárás visszatérési értéke -1 lesz. A karakterek pozíciója a szövegben 0-tól kezdődnek. A Text.Sub(t,p,l) eljárásnak három paramétere van: t a szöveg változó, p a pozíció, l pedig a hossz. Az eljárás a t szövegből p pozíciótól kezdve l darab karaktert kimásol, és szöveg típusukét adja vissza. A GetRealArray meglehetősen érzékeny eljárás. A fájlnak pontosan olyan adatokat kell tartalmaznia amilyet az eljárás vár; pl. nem tartalmazhat extra szóközöket Továbbá a fájlban lévő tömb méretének pontosan meg kell felelnie az r paraméter tömbnek. Rögzített formátumu fájl olvasása és írása:PROCEDURE GetRealArray(rd: Rd.T; VAR r: ARRAY OF REAL)= VAR i, delimiter: CARDINAL; t: TEXT; BEGIN WHILE NOT Rd.EOF(rd) DO t:= Rd.GetLine(rd); delimiter:= Text.FindChar(t, ' '); (*index és érték között *) i:= Scan.lnt(Text.Sub(t, 0, delimiter)); (*index számláló *) r[i]:= Scan.Real(Text.Sub(t, delimiter+l, Text.Length(t)-delimiter-1)); (*ertek *) END; (*WHILE*) END GetRealArray;
Rd, Wr jelzi, hogy írás vagy olvasás. Olvasás: t:=RD.GetLine(rd); vagy c:=Rd.GetChar(rd); file-vége tesztelése: Rd.EOF(rd) Speciális formájú adatok beolvasását segíti a Lex interface. Használatával lehetőségünk van egy input streamből egészet, valósat, vagy sztringet kiolvasni. Hasonló funkcionalitást nyújt sztringeken a Scan modul. Az interface három eljárást biztosít, amelyekkel 'üres', vagy 'nem-üres' karaktereket vizsgálhatunk a streamben.CONST NumbLength = 10; PROCEDURE PutRealArray(wr: Wr.T; READONLY r: ARRAY OF REAL)= BEGIN FOR i:= FIRST(r) TO LAST(r) DO (*iras allando hosszal *) Wr.PutText(wr, Fmt.Pad(Fmt.lnt(i), NumbLength) & Fmt.Pad(Fmt.Real(r[i]), NumbLength) &"\n"); END; (*FOR*) END PutRealArray; PROCEDURE GetRealArray(rd: Rd.T; VAR r: ARRAY OF REAL) _ VAR i: CARDINAL; BEGIN WHILE NOT Rd.EOF(rd) DO i:= Scan.lnt(Rd.GetText(rd, NumbLength)); (*index szamlalo*) r[i]:= Scan.Real(Rd.GetText(rd, NumbLength)); (*érték számláló*) EVAL Rd.GetLine(rd); (*skip EOL*) END; (*WHILE*) END GetRealArray;
Az eljárás addig olvassa a megadott streamet (rd), amíg el nem ér egy olyan karaktert, amelyik nincs benne cs-ben, vagy el nem éri a file végét. Visszatérési értékül a beolvasott stringet adja (az a karakter nem tartozik bele, amelyiknél megálltunk). Az eljárás után az olvasó pozíciója az a karakter, amelyiknél megálltunk - vagy a file vége.PROCEDURE Scan(rd: Rd.T; READONLY cs: SET OF CHAR := NonBlanks): TEXT RAISES {Rd.Failure, Alerted};
Az eljárás működése hasonló az előzőhöz, de itt nincs visszatérési érték, az eljárás "eldobja" a beolvasott szöveget. Például a Lex.Skip(rd); eljáráshívás elolvassa az input streamből az összes üres karaktert.PROCEDURE Skip(rd: Rd.T; READONLY cs: SET OF CHAR := Blanks) RAISES {Rd.Failure, Alerted};
Az eljárás ráilleszti az inputszöveget a 't' szövegre úgy, hogy a lehető leghosszabb karaktersorozatot olvassa, amelyik illeszkedik 't' karaktereinek sorozatára. Ha 't' nem illeszkedik teljesen, akkor 'Error' kivételt vált ki. A fenti konstansokat a következőképpen deklarálták:PROCEDURE Match(rd: Rd.T; t: TEXT) RAISES {Error, Rd.Failure, Alerted};
Továbbá műveleteket definiál különböző típusú objektumok beolvasására. Ezek a műveletek addig olvasnak a streamről, amíg csak lehet, kihagyva az 'üres' karaktereket. Ha a streamről nem lehet a megadott típusú objektumot kiolvasni, 'Error' kivétel váltódik ki.CONST Blanks = SET OF CHAR{ ' ', '\t', '\n', '\r', '\013' vertical tab , '\f'}; NonBlanks = SET OF CHAR{'!' .. '~'};
PROCEDURE Bool(rd: Rd.T): BOOLEAN RAISES {Error, Rd.Failure, Alerted}; PROCEDURE Int(rd: Rd.T; defaultBase: [2..16] := 10): INTEGER RAISES {Error, FloatMode.Trap, Rd.Failure, Alerted}; PROCEDURE Unsigned(rd: Rd.T; defaultBase: [2..16] := 16): Word.T RAISES {Error, FloatMode.Trap, Rd.Failure, Alerted}; PROCEDURE Real(rd: Rd.T): REAL RAISES {Error, FloatMode.Trap, Rd.Failure, Alerted}; PROCEDURE LongReal(rd: Rd.T): LONGREAL RAISES {Error, FloatMode.Trap, Rd.Failure, Alerted}; PROCEDURE Extended(rd: Rd.T): EXTENDED RAISES {Error, FloatMode.Trap, Rd.Failure, Alerted};