|
Bestands Invoer/Uitvoer
Een bestand aanmaken
Bestudeer het programma SCHRLIJN.C voor een eerste kennismaking met het
schrijven van gegevens naar een bestand. Ook hier begint het programma
met het toevoegen van stdio.h. Zoals gebruikelijk worden
enkele variabelen gedeclareerd, waaronder een van een merkwaardig type.
#include /* standard Invoer/Uitvoer header file */
main ()
{
int DS1, DS2, DS3, DS4, DS5; /* vijf dobbelstenen */
int index;
FILE *pf; /* pointer naar FILE */
DS1 = 2; DS2 = 3; DS3 = 4; DS4 = 5; DS5 = 6; /* initialiseer */
pf = fopen ("CURSUS.DAT", "w"); /* open voor schrijven */
for (index = 1; index <= 10; index ++) {
fprintf (pf, "Regel nummer %02d: %d %d %d %d %d\n",
index, DS1, DS2, DS3, DS4, DS5);
}
fclose (pf); /* sluit het bestand weer af */
}
Het type FILE wordt gebruikt voor een bestands variabele en
staat gedefinieerd in het bestand stdio.h. Dit type wordt
gebruikt bij het declareren van pointers naar bestanden, nodig bij
bestandsmanipulatie. De programmeertaal C vereist per definitie een
pointer naar een bestand. Deze pointer mag elke geldige variabele naam
hebben.
Voordat we in een bestand kunnen schrijven , moeten we het openen.
Concreet betekent dit dat we het systeem moeten vertellen dat we naar
een bestand willen schrijven en wat de naam van dat bestand is. We doen
dit met behulp van de fopen() funktie, zoals je in het
voorbeeld programma kunt zien. De funktie geeft als resultaat een
pointer naar een bestand terug aan de hand van de opgegeven invoer
parameters. In dit geval zal pf naar het bestand CURSUS.DAT
gaan wijzen. De bestandsnaam moet een geldige MS-DOS naam zijn en kan
zowel in kleine- als in hoofdletters worden opgegeven. De bestandsnaam
wordt als string aan de funktie aangeboden. Een waarschuwing is hier op
zijn plaats. Neem voor de bestandsnaam niet per ongeluk de naam van een
waardevol bestand. Het programma zal, zonder pardon, dit bestand
overschrijven, zodat de inhoud verloren gaat.
De tweede funktie parameter geeft aan hoe we het bestand willen
manipuleren. Door middel van de letter string "r", "w" of "a" kunnen we
aangeven welke operatie we willen uitvoeren. Met r geven we
aan dat we gegevens uit een bestand willen lezen, met w
geven we aan dat we gegevens naar een bestand willen schrijven en met
a geven we aan dat we gegevens aan een reeds bestaand
bestand willen toevoegen. Als we een bestand willen lezen, moet dit
bestand op schijf aanwezig zijn. Zoniet, dan zal de pointer naar het
bestand de waarde NULL krijgen. Op deze waarde kan worden getest.
Als een bestand is geopend voor schrijven, dan zal het worden
aangemaakt als het niet reeds op schijf aanwezig is. Is het een
bestaand bestand dan zal het van voor af aan herschreven worden,
waardoor reeds bestaande gegevens worden overschreven. Eventueel
aanwezige gegevens gaan daarmee dus verloren.
Als een bestand is geopend voor toevoegen, dan zal het worden
aangemaakt als het niet reeds op schijf aanwezig is. Is het een
bestaand bestand dan zullen de gegevens achter aan bijgeschreven
worden. Bestaande gegevens gaan dus niet verloren.
Uitvoer naar een bestand lijkt erg veel op standaard uitvoer. Het
verschil zit in de toegepaste funkties en het gebruik van de bestands
pointer. In het voorbeeld programma heeft fprintf() de
plaats ingenomen van de vertrouwde printf() funktie. De
bestands pointer is de eerste parameter, de andere parameters zijn
volkomen gelijk aan die van printf().
Een bestand moet na gebruik ook weer worden afgesloten. Dit doe je
met behulp van de fclose() funktie en de bestands
pointer als parameter.
Je kunt een bestand openen voor schrijven, sluiten, wederom openen voor
lezen, sluiten, openen voor toevoegen, enz. enz. Telkens kun je
dezelfde bestands pointer gebruiken of een andere. De pointer naar een
bestand is slechts een stukje gereedschap en je kunt zelf beslissen
naar welk bestand de pointer wijst.
Compileer en test dit programma. Het programma drukt niets af. Kijk na
afloop echter in het bestand CURSUS.DAT via de editor of middels het
MS-DOS type commando. Kijk of inhoud en programma
specificatie met elkaar overeen stemmen.
Een bestand uitbreiden
Het is ook mogelijk teken voor teken naar een bestand te schrijven.
Bestudeer programma SCHRCHAR.C voor een voorbeeld.
#include /* standard Invoer/Uitvoer header file */
main ()
{
int index;
char *pch; /* pointer naar char */
char regel[81] = "Tripple Yahtzee - pc3270"; /* regel met tekst */
FILE *pf; /* pointer naar FILE */
pf = fopen ("CURSUS.DAT", "a"); /* open voor toevoegen */
for (index = 1; index <= 10; index ++) {
for (pch = regel; *pch; pch++)
putc (*pch, pf);
putc ('\n', pf);
}
fclose (pf); /* sluit het bestand weer af */
}
Het programma begint met de declaratie van een lus variabele, een
pointer naar een character en een tabel van characters, die initieel
gevuld is met een tekst. Ook de pointer naar een bestand is nu niet
vreemd meer. Het bestand wordt vervolgens geopend voor toevoegen. Dit
is hetzelfde bestand van het vorige hoofdstuk, waardoor we in staat
zijn te controleren of het werkt.
Het programma bevat twee iteraties binnen elkaar. De buitenste lus
wordt 10 keer doorlopen om enkele regels uitvoer te genereren. De
binnenste lus wordt doorlopen totdat het teken uit de tekst string het
NULL karakter is. De pointer pch wijst het uit te voeren
teken aan en wijst telkens aan het begin van de iteratie naar het
eerste teken van de tekst string.
Interessant is nu de putc() funktie. Deze funktie schrijft
telkens 1 teken naar een bestand. Het teken is de eerste parameter. De
tweede parameter is de pointer naar het bestand waarin moet worden
geschreven.
Als alle tekens uit de tekst string weg zijn geschreven, wordt nog een
NewLine karakter toegevoegd, omdat deze niet in de tekst
zelf stond. Op deze wijze worden er 10 regels aan het bestand CURSUS.DAT
toegevoegd en het bestand wordt afgesloten. Compileer en test dit
programma en kijk of de regels inderdaad aan het einde van het bestand
zijn toegevoegd. Voer het programma nogmaals uit en kijk wat er
gebeurt.
Een bestand lezen
We gaan nu leren hoe een bestand kan worden gelezen. Bestudeer daartoe
nu het programma LEESCHAR.C. Het programma begint met het inmiddels
vertrouwde stdio.h bestand, de declaraties van wat
variabelen en het open statement.
#include /* standard Invoer/Uitvoer header file */
main ()
{
int letter; /* gelezen letter */
FILE *pf; /* pointer naar FILE */
pf = fopen ("CURSUS.DAT", "r"); /* open voor lezen */
if (pf == NULL)
printf ("Het bestand 'CURSUS.DAT' is niet gevonden\n");
else
do {
letter = getc (pf); /* lees een letter */
putchar (letter); /* druk de letter af */
} while (letter != EOF); /* tot einde bestand */
fclose (pf); /* sluit het bestand weer af */
}
De tweede parameter is nu de kleine letter r, ten teken dat
we het bestand willen lezen. Tevens controleren we of het bestand op
schijf aanwezig is. Zoniet dan volgt een fout boodschap. Zo ja dan
wordt een iteratie gestart. Teken voor teken wordt gelezen en afgedrukt
tot einde bestand (EOF). Het bestand wordt dan afgesloten en het
programma stopt.
Kijk nog eens goed naar de declaratie van de variabele
letter. Je ziet dat deze gedeclareerd wordt als zijnde van
het type integer. Het gaat hier om een character, dus char
zou in principe moeten voldoen. Het is echter zo dat de meeste C
compilers EOF gedefinieerd hebben als symbolische constante met de
waarde -1. Die waarde past niet in een char variabele, dus
een waarschuwing is hier op zijn plaats. Gebruik altijd een
int variabele wanneer vergeleken wordt met de constante EOF.
Compileer en test dit programma. Als alles werkt zoals je verwacht,
verander dan de naam van het bestand in de fopen() in
ISERNIET.DAT. Compileer en test het programma dan opnieuw.
Woorden lezen uit een bestand
Bestudeer nu het programma LEESTEXT.C waarin wordt uitgelegd hoe
een bestand woord voor woord te lezen.
#include /* standard Invoer/Uitvoer header file */
main ()
{
int rc; /* return code */
char woord[81]; /* gelezen woord */
FILE *pf; /* pointer naar FILE */
pf = fopen ("CURSUS.DAT", "r"); /* open voor lezen */
do {
rc = fscanf (pf, "%s ", woord); /* lees een woord */
printf ("%s\n", woord); /* druk het woord af */
} while (rc != EOF); /* tot einde bestand */
fclose (pf); /* sluit het bestand weer af */
}
Dit programma gebruikt de fscanf() funktie om een woord te
lezen. Omdat fscanf() het lezen stopt bij het vinden van een
spatie of een NewLine karakter, zal woord voor woord uit het
bestand gelezen worden. Elk gelezen woord wordt op een nieuwe regel
afgedrukt. Compileer en test het programma.
Er is een klein probleem met dit programma. Het programma leest een
woord, drukt dit af en test op EOF, leest een woord, drukt dit af en
test op EOF, enz. enz. Door deze manier van werken wordt de
EOF zelf ook verwerkt, immers de test is achteraf. Het
resultaat is dat het laatste woord uit het bestand twee keer wordt
afgedrukt. Dit is niet wat we willen.
Het probleem valt op te lossen door de test op EOF vooraf te doen. Dit
kan, zo hebben we geleerd, met behulp van het while
statement. Bestudeer het programma LEESGOED.C. Het wordt hier niet
verder besproken. Je moet nu in staat zijn dit programma te begrijpen.
#include /* standard Invoer/Uitvoer header file */
main ()
{
char woord[81]; /* gelezen woord */
FILE *pf; /* pointer naar FILE */
pf = fopen ("CURSUS.DAT", "r"); /* open voor lezen */
while ((fscanf (pf, "%s", woord)) != EOF) /* lees een woord */
printf ("%s\n", woord); /* druk het woord af */
fclose (pf); /* sluit het bestand weer af */
}
Compileer en test ook dit programma.
Regels lezen uit een bestand
Bestudeer nu het programma LEESLIJN, waarin wordt uitgelegd hoe een
complete regel (ook wel record genoemd) uit een bestand kan worden
gelezen. Dit programma lijkt als twee druppels water op het LEESGOED.C
programma, echter nu wordt gewerkt met de fgets() funktie en
er wordt getest op het NULL karakter.
#include /* standard Invoer/Uitvoer header file */
main ()
{
char regel[81]; /* gelezen regel */
FILE *pf; /* pointer naar FILE */
pf = fopen ("CURSUS.DAT", "r"); /* open voor lezen */
while ((fgets (regel, 100, pf)) != NULL) /* lees een regel */
printf ("%s", regel); /* druk de regel af */
fclose (pf); /* sluit het bestand weer af */
}
De fgets() funktie leest regel voor regel uit een bestand,
inclusief het NewLine karakter. Het resultaat komt in de
buffer die we als eerste parameter meegeven. Het maximum aantal tekens
dat mag worden gelezen staat in de tweede parameter. De derde parameter
is de pointer naar het te lezen bestand. De funktie leest tekens in de
buffer totdat ofwel het NewLine karakter wordt gevonden,
ofwel het maximum aantal tekens minus 1 werd gelezen. Er blijft dan nog
een teken in de buffer beschikbaar voor het NULL karakter. Bij het
lezen van EOF, wordt NULL terug gegeven als funktie waarde. In het
voorbeeld programma wordt direct op deze NULL waarde getest.
Door de constructie met de while wordt de test vooraf gedaan
en werkt het programma verder correct. Bij het bereiken van EOF wordt
het bestand gesloten en stopt het programma. Compileer en test ook dit
programma.
Een willekeurig bestand inlezen
We kunnen het programma LEESLIJN.C nog iets uitbreiden, nog iets
algemener maken. Bestudeer nu programma LEESBEST.C om te zien hoe dat
gaat.
#include /* standard Invoer/Uitvoer header file */
main ()
{
char best_naam[32]; /* bestandsnaam */
char regel[81]; /* gelezen regel */
FILE *pf; /* pointer naar FILE */
printf ("Tik de naam van een bestand in:\n");
scanf ("%s", best_naam); /* lees bestandsnaam */
pf = fopen (best_naam, "r"); /* open voor lezen */
while ((fgets (regel, 100, pf)) != NULL) /* lees een regel */
printf ("%s", regel); /* druk de regel af */
fclose (pf); /* sluit het bestand weer af */
}
Er is een extra buffer (best_naam) gedeclareerd, waarin de
naam van een bestand geplaatst kan worden. Het programma vraagt de
gebruiker de naam van een bestand in te tikken. Middels
scanf wordt deze bestandsnaam in de buffer gelezen en volgt
de open opdracht voor dit bestand. De fopen() funktie
verwacht als eerste parameter een pointer naar een tabel van
characters. Zowel een tekst string als de variabele
best_naam voldoen aan deze eis. Hierdoor wordt het mogelijk
op uitvoeringstijd een bestand aan te wijzen voor verwerking.
Het bestand wordt vervolgens regel voor regel gelezen en afgedrukt.
In feite komt dit programma overeen met het MS-DOS type
commando.
Compileer en test dit programma. Tik, wanneer het programma daar om vraagt,
de naam in van een bestand wat op schijf aanwezig is. Dit mag dus ook
de naam van een van de C programma's zijn.
|