Streams en bestanden in C#

  1. Inleiding
  2. Streams
  3. FileStream
  4. StreamWriter/Reader
  5. File
  6. Slot
  7. Voorbeeldprogramma

Inleiding

We hebben het in eerdere posts gehad over geheugenvarabelen en collecties en daar begint het opslaan van gegevens meestal ook mee. Bij geheugenvariabelen en collecties staat alles in het geheugen, maar alles is weg zodra je de applicatie afsluit en de computer uitzet.

Het wordt allemaal wat permanenter als we gegevens in een bestand op de harde schijf kunnen opslaan en weer kunnen opvragen. Het gebruik van bestanden gaat in de praktijk meestal gepaard met het gebruik van “streams“, maar het stream concept betreft alle opslagmedia en niet alleen maar bestanden. In deze post meer over streams en bestanden.

up | down

Streams

Bij streams is de Stream klasse een abstracte klasse waar andere klassen uit erven. De kinderen van de Stream klasse zijn allemaal gespecialiseerd in een bepaald medium waarbij elk medium weer zijn eigen karakteristieken heeft.

Zo zijn bestanden de specialiteit van de FileStream klasse en een padnaam is tamelijk relevant voor de FileStream klasse omdat anders het bestand niet gevonden kan worden. De MemoryStream klasse (een ander kind van de FileStream) is gespecialiseerd in geheugenlocaties en de MemoryStream is niet geïnteresseerd in namen van paden, maar wel weer in zaken die voor de FileStream weer niet interessant zijn.

Hoe de bytes correct worden weggeschreven en hoe die bytes opgevraagd moeten worden uit een bepaald medium? Daar houdt de Stream klasse zich niet mee bezig, dat wordt weer geregeld door de kinderen die van haar erven en gespecialiseerd zijn in een bepaald opslagmedium.

De FileStream klasse is niet de enige klasse die erft van de Stream klasse en die gespecialiseerd is in datgene wat met bestanden te maken heeft. We hebben ook nog een StreamWriter/Reader klasse en een File klasse. We zullen alledrie de klassen in deze post bespreken.

up | down

FileStream

We gebruiken in onderstaand voorbeeld de File klasse voor de aanmaak van een bestand. Verder wordt in het voorbeeld de FileStream klasse gebruikt om het bestand te vullen en om het bestand uit te lezen. We zien dat we bij de FileStream klasse gebruik moeten maken van byte arrays. Alles moet in een byte array gezet worden en met die byte array gaan we verder.

Computers kunnen alleen (nog) maar nulletjes en eentjes opslaan. Wat gaat een computer doen als het op jouw verzoek een bestand opent en de inhoud aan jou moet tonen en bijvoorbeeld een byte tegenkomt met deze inhoud: 0100 001? Het antwoord is dat hij dan een character encoding tabel gaat raadplegen zodat hij weet wat hij aan jou moet laten zien.

Zo zullen we in de meeste character encoding tabellen (ASCII, UTF-8, UTF-16 etc.) voor byte inhoud 0100 001 (=65 decimaal) een hoofdletter A vinden en die hoofdletter krijg je dan ook te zien. De System.Text.UTF8Encoding character encoding tabel is de meest gangbare character encoding tabel.

Het kan voorkomen dat een bestand een tekst bevat dat geschreven is in een vreemde exotische taal. De computer zal dan een speciale character encoding tabel nodig hebben om alles fatsoenlijk getoond te doen krijgen, maar dan ben je er nog niet want je zult ook een lettertype (font) moeten hebben dat alle karakters van die taal ondersteunt. In onderstaand voorbeeld zien we dat we met UTF8Encoding gebruik maken van de UTF-8 character encoding tabel.

 // Het bestand
 bestandsnaam = "FileStream.txt";
 Console.WriteLine("De FileStream klasse.");
      
 // Aanmaken en vullen bestand
 using (FileStream fileStream = 
        File.Create(pad + bestandsnaam))
 {
   Console.WriteLine(
   "- Aangemaakt bestand: {0}", bestandsnaam);
   tekstje = "abc";
   Console.WriteLine(
   "- Dit schrijven we weg: {0}",tekstje);
   byte[] wegTeSchrijvenBytes = 
   new UTF8Encoding(true).GetBytes(tekstje);
   fileStream.Write(
   wegTeSchrijvenBytes, 0, 
   wegTeSchrijvenBytes.Length);
 }
       
 // Lezen bestand
 using (FileStream fileStream = 
        File.OpenRead(pad + bestandsnaam))
 {
    int totaalAantalBytes = 
    (int)fileStream.Length;
    byte[] inGeLezenBytes = 
    new byte[totaalAantalBytes];
          
    fileStream.Read(inGeLezenBytes, 0, 
                    totaalAantalBytes);
    tekstje = 
    Encoding.UTF8.GetString(inGeLezenBytes);
    Console.WriteLine(
    "- Dit staat in het bestand: {0}",
    tekstje);
 }

De FileStream klasse is een afgeleide van de Stream klasse en we kunnen het fileStream object terug casten naar een stream object. De Stream klasse denkt alleen maar in bytes en we gebruiken dan ook een eigenschap length om te kunnen zien wat de lengte is van de stream:

// De stream zelf
using (FileStream fileStream = 
       File.OpenRead(pad + 
       bestandsnaam))
{
  // De stream zelf
  Stream stream = (Stream)fileStream;
  Console.WriteLine(
  "- Lengte van de Stream: {0} bytes",
  stream.Length);
}

up | down

StreamWriter/Reader

Als het gaat om tekstbestanden dan kunnen ook de StreamWriter en de StreamReader klassen gebruikt worden. We zien bij deze klasse dat we geen byte arrays hoeven te gebruiken.

In onderstaand voorbeeld geven we bij het instantiëren naar een StreamWriter– of StreamReader-object één parameter mee aan de constructor en dat is het bestand waaruit gelezen moet worden of waarnaar geschreven moet worden. Als tweede parameter kun je eventueel ook een character encoding tabel meegeven, maar meestal hoef je geen character encoding tabel mee te geven en volstaan de defaults.

// Het bestand
bestandsnaam 
= "StreamWriterReader.txt";

Console.WriteLine(
"\r\nDe StreamWriter/Reader klasse.");
        
// StreamWriter
using (StreamWriter streamWriter = 
       File.CreateText(pad + bestandsnaam))
{
  Console.WriteLine(
  "- Aangemaakt bestand: {0}", bestandsnaam);
  tekstje = "def";
  Console.WriteLine(
  "- Dit schrijven we weg: {0}", tekstje);
  streamWriter.Write(tekstje);
}
       
// StreamReader
using (StreamReader streamReader = 
       File.OpenText(pad + bestandsnaam))
{
  tekstje = streamReader.ReadToEnd();
  Console.WriteLine(
  "- Dit staat in het bestand: {0}", 
  tekstje);
}       

up | down

File

De File Class hadden we al gebruikt om een bestand aan te maken, maar we kunnen deze klasse ook gebruiken om o.a. een bestand uit te lezen. Verdere specialismen van de File klasse zijn o.a. bestandsattributen en diverse handelingen m.b.t. bestanden zoals kopiëren, verwijderen en verplaatsen.

// Het bestand
bestandsnaam = "FileClass.txt";
Console.WriteLine(
"\r\nDe File klasse.");

tekstje = "ghi";

Console.WriteLine(
"- Aangemaakt bestand: {0}", 
   bestandsnaam);

Console.WriteLine(
"- Dit schrijven we weg: {0}", 
   tekstje);

File.WriteAllText(
  pad + bestandsnaam, tekstje);

tekstje = 
File.ReadAllText(pad + bestandsnaam);

Console.WriteLine(
"- Dit staat in het bestand: {0}", 
tekstje);

up | down

Slot

De Stream klasse is een abstracte klasse waar andere klassen uit erven. De kinderen van de Stream klasse zijn allemaal gespecialiseerd in een bepaald medium waarbij elk medium weer zijn eigen karakteristieken heeft. Zo zal het medium het geheugen zijn als we dingen willen wegschrijven naar het geheugen en zo zal het medium een bestand zijn als we iets willen wegschrijven naar een bestand.

Het .NET framework heeft een aantal klassen die erven van de Stream klasse en die gespecialiseerd zijn in datgene wat met bestanden te maken heeft. Deze klassen zijn de FileStream, de StreamWriter, de StreamReader en de File en ik heb in deze post laten zien hoe je met die klassen een tekstbestand kan aanmaken en hoe je het tekstbestand kunt vullen en kunt uitlezen.

Hopelijk ben je met deze posting weer wat wijzer geworden en ik hoop je weer terug te zien in één van mijn volgende blog posts. Wil je weten wat ik nog meer over C# heb geschreven? Hit the C# button…

up | down


Voorbeeldprogramma

using System;
using System.IO;
using System.Text;

namespace voorbeeld
{
  class MainClass
  {
    public static void Main(string[] args)
    {
      // pad
      string pad = @" ..... ";
      string tekstje = null;
      string bestandsnaam;
      
      /*
       * ----------
       * FileStream
       * ----------
       *
       */
      // Het bestand
      bestandsnaam = "FileStream.txt";
      Console.WriteLine("De FileStream klasse.");
      
      // Aanmaken en vullen bestand
      using (FileStream fileStream = 
             File.Create(pad + bestandsnaam))
      {
         Console.WriteLine(
         "- Aangemaakt bestand: {0}", bestandsnaam);
         tekstje = "abc";
         Console.WriteLine(
         "- Dit schrijven we weg: {0}",tekstje);
         byte[] wegTeSchrijvenBytes = 
         new UTF8Encoding(true).GetBytes(tekstje);
         fileStream.Write(
           wegTeSchrijvenBytes, 0, 
           wegTeSchrijvenBytes.Length);
       }
       
       // Lezen bestand
       using (FileStream fileStream = 
              File.OpenRead(pad + bestandsnaam))
       {
         int totaalAantalBytes = 
         (int)fileStream.Length;
         byte[] inGeLezenBytes = 
         new byte[totaalAantalBytes];
         
         fileStream.Read(inGeLezenBytes, 0, 
                         totaalAantalBytes);
         tekstje = 
         Encoding.UTF8.GetString(inGeLezenBytes);
         Console.WriteLine(
         "- Dit staat in het bestand: {0}",
          tekstje);
       }
       
       // De stream zelf
       using (FileStream fileStream = 
              File.OpenRead(pad + 
              bestandsnaam))
       {
         // De stream zelf
         Stream stream = (Stream)fileStream;
         Console.WriteLine(
         "- Lengte van de Stream: {0} bytes",
         stream.Length);
       }
       
       /*
        * -------------------
        * StreamWriter/Reader
        * -------------------
       */
       // Het bestand
       bestandsnaam 
       = "StreamWriterReader.txt";
       Console.WriteLine(
       "\r\nDe StreamWriter/Reader klasse.");
        
       // StreamWriter
       using (StreamWriter streamWriter = 
              File.CreateText(pad + bestandsnaam))
       {
         Console.WriteLine(
         "- Aangemaakt bestand: {0}", bestandsnaam);
         tekstje = "def";
         Console.WriteLine(
         "- Dit schrijven we weg: {0}", tekstje);
         streamWriter.Write(tekstje);
       }
       
       // StreamReader
       using (StreamReader streamReader = 
              File.OpenText(pad + bestandsnaam))
       {
         tekstje = streamReader.ReadToEnd();
         Console.WriteLine(
         "- Dit staat in het bestand: {0}", 
          tekstje);
       }
       
       /*
        * ----
        * File
        * ----
        * 
       */
       // Het bestand
       bestandsnaam = "FileClass.txt";
       Console.WriteLine(
       "\r\nDe File klasse.");
       tekstje = "ghi";
       Console.WriteLine(
       "- Aangemaakt bestand: {0}", 
          bestandsnaam);
       Console.WriteLine(
       "- Dit schrijven we weg: {0}", 
          tekstje);
       File.WriteAllText(
       pad + bestandsnaam, tekstje);
       tekstje = 
       File.ReadAllText(pad + bestandsnaam);
       Console.WriteLine(
       "- Dit staat in het bestand: {0}", 
       tekstje);
    }
  }
}

up | down

Resultaat

De FileStream klasse.
- Aangemaakt bestand: FileStream.txt
- Dit schrijven we weg: abc
- Dit staat in het bestand: abc
- Lengte van de Stream: 3 bytes

De StreamWriter/Reader klasse.
- Aangemaakt bestand: StreamWriterReader.txt
- Dit schrijven we weg: def
- Dit staat in het bestand: def

De File klasse.
- Aangemaakt bestand: FileClass.txt
- Dit schrijven we weg: ghi
- Dit staat in het bestand: ghi

up

Laat een reactie achter

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *