n00b pro

05. Bestanden en mappen

Dit hoofdstuk is onderdeel van de cursus C#. Andere cursussen in dezelfde reeks: HTML, CSS, Javascript, Ontwikkelomgeving.

Youtube: bestanden & excepties

https://www.youtube.com/watch?v=j-ECPszC8x8

Namespaces en klassen

In .NET zit de functionaliteit voor het werken met bestanden en mappen verspreid over heel wat namespaces en klassen.

Voor paden

Klasse Omschrijving
System.IO.Path werken met paden; methodes Combine(), GetFileNameWithoutExtension(), GetDirectoryName()...
System.Environment omgevingsspecifieke paden; methodes GetFolderPath(), properties SpecialFolder.Desktop, SpecialFolder.MyDocuments...

Voor bestanden en mappen

De meeste klassen voor het werken met bestanden en mappen vind je in de System.IO namespace:

Klasse Omschrijving
Directory werken met mappen; methodes GetDirectories(), GetFiles(), Delete(), CreateDirectory()...
DirectoryInfo map informatie opvragen; properties FullName, Name, Parent, Exists...
File werken met bestanden; methodes ReadAllText(), WriteAllText(), Copy(), Delete()...
FileInfo bestand informatie opvragen; properties Name, Extension, Directory, Exists, Length...
StreamReader bestanden streamend lezen (geheugenvriendelijk, enkel nodig bij zeer grote bestanden)
StreamWriter bestanden streamend schrijven (geheugenvriendelijk, enkel nodig bij zeer grote bestanden)
System.IO.Path werken met paden; methodes Combine(), GetFileNameWithoutExtension(), GetDirectoryName()...

Voor dialoogvensters

Allerhande dialoogvensters vind je in Microsoft.Win32, System.Windows en System.Windows.Forms:

Namespace Klasse Omschrijving
Microsoft.Win32 OpenFileDialog dialoogvenster om bestanden te openen
Microsoft.Win32 OpenFolderDialog dialoogvenster om mappen te openen — pas beschikbaar vanaf .NET8!
Microsoft.Win32 SaveFileDialog dialoogvenster om bestanden op te slaan
System.Windows MessageBox foutmeldings-, waarschuwings- en berichtvensters
System.Windows.Forms FolderBrowserDialog ouderwets dialoogvenster om een map te kiezen

Paden

Systeemmappen vinden

Op elke computer is de fysieke locatie voor systeemmappen als Desktop, My Documents... verschillend. Gebruik daarom altijd de Environment.SpecialFolder enumeratie:

string desktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

Andere typische voorbeelden zijn My Documents, My Pictures enz...:

Paden combineren

Gebruik best altijd System.IO.Path.Combine() om paden te combineren:

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "textfiles\\myfile.txt");
Console.WriteLine(filePath);
C:\Users\rogie\Documents\textfiles\myfile.txt
resultaat in de console

Bestanden

Overzicht

Alle methodes om bestanden te lezen, schrijven, bewerken enz... vind je in de File klasse:

Methode Omschrijving
AppendAllLines() array of lijst toevoegen aan een bestand
AppendAllText() tekst toevoegen aan een bestand
Copy() kopieer een bestand
Delete() verwijder een bestand
Exists() controleert of een bestand bestaat
Move() verplaats een bestand
ReadAllLines() bestand inlezen in een string[] array
ReadAllText() bestand inlezen in een string
WriteAllLines() array of lijst keer schrijven naar een bestand
WriteAllText() tekst schrijven naar een bestand

Properties om bestandsinformatie op te vragen vind je in de FileInfo klasse:

Property Omschrijving
Directory map van het bestand (volledig pad)
DirectoryName mapnaam van het bestand
Exists bestaat het of niet (true of false)
Extension extensie (met punt)
FullName volledig pad
Length bestandsgrootte in bytes
Name bestandsnaam

Code voorbeelden

Bestand inlezen in een string

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");

string inhoud = File.ReadAllText(filePath); // lees tekstinhoud bestand in

Bestand inlezen in een array

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");

string[] regels = File.ReadAllLines(filePath); // lees regels bestand in

String schrijven naar een bestand

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");
string inhoud = @"Dit is regel 1
Dit is regel 2";

File.WriteAllText(filePath, inhoud); // nieuw bestand als het nog niet bestaat

Array of lijst schrijven naar een bestand

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");
string[] regels = new string[] { "Dit is lijn 1", "Dit is lijn 2" };

File.WriteAllLines(filePath, regels); // nieuw bestand als het nog niet bestaat

Tekst toevoegen aan een bestaand bestand

Naast File.WriteAllText() en File.WriteAllLines() bestaan er ook methodes File.AppendAllText() en File.AppendAllLines():

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");

File.AppendAllText(filePath, $"Am no an listening depending up believing{Environment.NewLine}");
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");
string[] regels = new string[] { "Dit is lijn 3", "Dit is lijn 4" };

File.AppendAllLines(filePath, regels); 

Controleren of een bestand bestaat

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "mycontacts.txt");

if (!File.Exists(filePath)) 
{
   // ...
}

Informatie opvragen

Twee klassen bieden gedeeltelijk overlappende functionaliteit voor het opvragen van informatie: FileInfo en Path.

Codevoorbeeld met FileInfo (bestand “test.txt” op de Desktop):

string filePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.txt");
FileInfo fi = new FileInfo(filePath);
Console.WriteLine($@"
bestandsnaam: {fi.Name} 
extensie: {fi.Extension} 
gemaakt op: {fi.CreationTime.ToString()} 
mapnaam: {fi.Directory.Name} 
");
bestandsnaam: test.txt
extensie: .txt
gemaakt op: 24/10/2023 19:45:16
mapnaam: Desktop
resultaat in de console

Codevoorbeeld met Path: (bestand “test.txt” op de Desktop):

string filePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.txt");
Console.WriteLine($@"
bestandsnaam: {Path.GetFileName(filePath)} 
bestandsnaam zonder extensie: {Path.GetFileNameWithoutExtension(filePath)} 
extensie: {Path.GetExtension(filePath)} 
map: {Path.GetDirectoryName(filePath)} 
");
bestandsnaam: test.txt
bestandsnaam zonder extensie: test
extensie: .txt
map: C:\Users\rogier\Desktop
resultaat in de console

Streamend lezen en schrijven

Alle vorige methodes laden de hele bestandsinhoud in één keer in het geheugen in. Voor heel grote bestanden is dat niet efficiënt. In die (uitzonderlijke) gevallen kan je gebruik maken van StreamReader en StreamWriter.

StreamReader voorbeeld (zoeken naar een tekst):

List<string> foundLines = new List<string>();
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "mycontacts.txt");

// open stream and start reading
using (StreamReader reader = File.OpenText(filePath)) {
    string line;
    while ((line = reader.ReadLine()) != null) {
        if (line.Contains("jennifer")) foundLines.Add(line);
    }
} // stream closes automatically

StreamWriter voorbeeld:

// prepare
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = System.IO.Path.Combine(folderPath, "myfile.txt");

// open stream and start writing
using (StreamWriter writer = File.CreateText(filePath)) {
    writer.WriteLine("Dit is lijn 1");
    writer.WriteLine("Dit is lijn 2");
} // stream closes automatically

In praktijk zul je streamend lezen of schrijven in deze cursus nooit nodig hebben.

Mappen

Overzicht

Alle methodes om te werken met mappen vind je in de Directory klasse:

Methode Omschrijving
CreateDirectory() maak een map aan
Delete() verwijder een map
Exists() controleert of een map bestaat
GetDirectories() vraag een lijst submappen in de map op
GetFiles() vraag een lijst bestanden in de map op

Properties om mapinformatie op te vragen vind je in de DirectoryInfo klasse:

Property Omschrijving
Exists bestaat het of niet (true of false)
FullName volledig pad
Name bestandsnaam
Parent basismap (volledig pad)

Code voorbeelden

Map inhoud lezen

Gebruik de methodes GetDirectories en GetFiles. Voorbeeld voor het lezen van de bestanden op de desktop:

string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

string[] files = Directory.GetFiles(desktop); // lijst van bestanden (volledig pad)
foreach (string file in files)
{
    Console.WriteLine(new FileInfo(file).Name); // geef enkel de namen weer
}

Controleren of een map bestaat

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string startfolder = System.IO.Path.Combine(folderPath, "myfolder");

if (!Directory.Exists(startfolder)) 
{
   // ...
}

Informatie opvragen

Gebruik de DirectoryInfo klasse om informatie op te vragen. Schematisch codevoorbeeld (map “Odisee” op de desktop):

string folderPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Odisee");
DirectoryInfo di = new DirectoryInfo(folderPath);
Console.WriteLine($@"
mapnaam: {di.Name}
basismap: {di.Parent.Name}
gemaakt op: {di.CreationTime}
");
mapnaam: Odisee
basismap: Desktop
gemaakt op: 29/01/2023 15:46:31
resultaat in de console

Dialoogvensters

OpenFileDialog

Schematisch:

OpenFileDialog dialog = new OpenFileDialog();
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
dialog.Filter = "Tekstbestanden|*.TXT;*.TEXT";
string chosenFileName;
bool? dialogResult = dialog.ShowDialog();
if (dialogResult == true) { 
   // user picked a file and pressed OK
   chosenFileName = dialog.FileName; 
} else {
    // user cancelled or escaped dialog window
}

OpenFolderDialog

Let op! Tot voor kort bestond (zeer vreemd genoeg) dit dialoogvenster niet. Het is pas toegevoegd sinds .NET8, dus werkt niet in oudere projecttypes als WPF .NET Framework! Daar werd je verondersteld third party oplossingen te gebruiken. Schematisch:

OpenFolderDialog dialog = new OpenFolderDialog();
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string chosenFolderName;
bool? dialogResult = dialog.ShowDialog();
if (dialogResult == true)
{
    // user picked a folder and pressed OK
    chosenFolderName = dialog.FolderName;
}
else
{
    // user cancelled or escaped dialog window
}

SaveFileDialog

Schematisch:

SaveFileDialog dialog = new SaveFileDialog();
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
dialog.Filter = "Tekstbestanden|*.TXT;*.TEXT";
dialog.FileName = "savedfile.txt";
if (dialog.ShowDialog() == true) {
    File.WriteAllText(dialog.FileName, "tekstinhoud hier");
} else {
    // user pressed Cancel or escaped dialog window
}

MessageBox

Zie .NET classes - MessageBox