Tot nu toe kwamen alle gegevens van je programma via het toetsenbord binnen (met
Console.ReadLine()) en verdwenen de resultaten weer zodra het programma stopte.
Maar vaak wil je gegevens bewaren of hergebruiken: een ledenlijst, de
scores van een spel, de resultaten van een toets. Daarvoor gebruik je
bestanden.
Werken met sequentiële tekstbestanden is een eenvoudige en handige manier om gegevens te verzamelen of om gegevens uit een ander programma te verwerken. Denk aan een programma zoals Excel: daar kan je gegevens exporteren naar een tekstformaat (bijvoorbeeld CSV, comma separated values). Met C# kan je dat tekstbestand dan inlezen, er berekeningen op uitvoeren die in Excel lastig zijn, of de gegevens omvormen naar een ander formaat.
Een sequentieel tekstbestand lees je van voor naar achter, regel per regel, net zoals je een boek van de eerste tot de laatste bladzijde leest. Elke regel in het bestand komt overeen met één
Console.ReadLine().
Om met bestanden te werken heb je twee hulpmiddelen nodig:
StreamReader om uit een bestand te lezen;StreamWriter om naar een bestand te schrijven.Beide zijn ingebouwd in C# en horen bij de naamruimte System.IO. Op Dodona is
die naamruimte al voor je beschikbaar, dus je kan StreamReader en
StreamWriter meteen gebruiken zonder iets extra te schrijven.
Het onderstaande programma toont alle elementen samen. Het leest een bestand
invoerBestand.txt regel per regel in en schrijft elke regel weg naar een
nieuw bestand uitvoerbestand.txt.
StreamReader invoerBestand = new StreamReader("invoerBestand.txt");
StreamWriter uitvoerBestand = new StreamWriter("uitvoerbestand.txt", false);
string invoerlijn;
while (!invoerBestand.EndOfStream)
{
invoerlijn = invoerBestand.ReadLine();
uitvoerBestand.WriteLine(invoerlijn);
}
uitvoerBestand.Close();
invoerBestand.Close();
Console.WriteLine("klaar");
Stap voor stap:
StreamReader aan en geeft als parameter de naam van het
bestand dat je wil lezen: new StreamReader("invoerBestand.txt").StreamWriter aan voor het bestand dat je wil schrijven:
new StreamWriter("uitvoerbestand.txt", false). De tweede parameter false
betekent dat je een nieuw bestand maakt (een bestaand bestand met die naam
wordt overschreven). Zet je daar true, dan wordt je uitvoer juist
achteraan toegevoegd aan het bestaande bestand.!invoerBestand.EndOfStream controleer je of er nog invoer
is. Zolang het einde van het bestand nog niet bereikt is, lees je met
ReadLine() één regel en schrijf je die met WriteLine() naar het
uitvoerbestand.Close(). Dat is nodig om de
bestanden terug vrij te geven aan het besturingssysteem. Bij een uitvoerbestand
zorgt Close() er ook voor dat de inhoud effectief op de schijf terechtkomt.Vergeet
Close()niet, zeker niet bij eenStreamWriter. Sluit je het uitvoerbestand niet, dan kan het gebeuren dat je geschreven regels nooit echt worden bewaard.
In plaats van EndOfStream kan je een bestand ook lezen tot ReadLine() geen
regel meer teruggeeft. ReadLine() geeft dan null terug, en daar stop je op:
StreamReader bestand = new StreamReader("woorden.txt");
string regel;
while ((regel = bestand.ReadLine()) != null)
{
Console.WriteLine(regel);
}
bestand.Close();
Allebei de manieren zijn goed. Combineer dit lezen gerust met wat je eerder al
leerde: een ingelezen regel kan je met Split() opdelen in stukken, omzetten
naar een getal met Convert.ToInt32(), of bewaren in een array.
Op Dodona hoef je je geen zorgen te maken over waar je bestand staat. Het gegevensbestand wordt automatisch klaargezet in dezelfde map als je programma. Je opent het dus gewoon met zijn naam, zonder volledig pad:
StreamReader bestand = new StreamReader("invoerBestand.txt");
Bij de oefeningen die volgen, krijg je telkens te horen welk bestand er beschikbaar is en hoe een record in dat bestand er precies uitziet. Je leest dat bestand dan in, verwerkt de gegevens, en drukt enkel het gevraagde resultaat af.
Werken met bestanden kan op nog veel meer manieren (en je kan met C# ook gegevens uit een echte databank verwerken), maar voor de oefeningen in deze cursus volstaat deze eenvoudige aanpak met
StreamReaderenStreamWriter.