.
Anmeldung | Registrieren | Hilfe |
Suchen
Home Foren News Member Offers Termine Developer Blogs Knowledge Base

Navigation

Navigationslinks überspringen.
Knowledge Base reduzierenKnowledge Base
Tutorials reduzierenTutorials
Webentwicklung
Cliententwicklung
Datenbankentwicklung
IT Professional
Sharepoint
Sprachspezifisch reduzierenSprachspezifisch
C#
Visual Basic
C++
XAML
SQL
JavaScript
Erfahrungsberichte reduzierenErfahrungsberichte
Entwicklersoftware
Bücher
FAQ Grundlagen

Verknüpfungen

  • Knowledge Base durchsuchen
  • Hilfe zur Knowledge Base
  • RSS Feed
  • Twitter

Erweiterungsmethoden: IO-Extensions

Ich stelle euch heute ein Anwendungsbeispiel für Erweiterungsmethoden vor, dass die Arbeit mit Ordner und Dateien etwas erleichtert. Das Erstellen von FileStream-Objects fällt somit weg.

 

Erst etwas Grundlegendes

Mit Erweiterungsmethoden ist es möglich für vorhandene Klassen oder Strukturen zusätzliche Methoden zu schreiben. Es können auch Klassen vom .NET-Framework selbst erweitert werden. Genauere erklärungen findet ihr genügend im Internet.

 

Kurzes Beispiel:

Wir wollen die Anzahl der Ziffern einer Zahl ermitteln und diese als Text ausgeben.

Lösung ohne Erteiterungsmehoden:
1: static void Main(string[] args)
2: {
3:  
4:     int number = 65823598;
5:  
6:     Console.WriteLine(countDigits(number));
7:  
8:     Console.ReadLine();
9:  
10:     
11: }
12:  
13: private static string countDigits(int _number)
14: {
15:     return _number.ToString().Length.ToString();
16: }
Lösung mit Erweiterungsmethoden:
1: using System;
2: using AdInt;
3:  
4: namespace TestConsole
5: {
6:     class Program
7:     {
8:  
9:         static void Main(string[] args)
10:         {
11:  
12:             int number = 65823598;
13:  
14:             Console.WriteLine(number.countDigits());
15:  
16:             Console.ReadLine();
17:         }
18:  
19:     }
20: }
21:  
22: namespace AdInt
23: {
24:     using System;
25:  
26:     public static class IntegerExtension
27:     {
28:         public static string countDigits(this int _number)
29:         {
30:             return _number.ToString().Length.ToString();
31:         }
32:     }
33: }

Schreibtechnisch bringt uns dieses Beispiel eher Nachteile, aber man kann hier deutlich sehen, dass die Methode jetzt zur Klasse Int(32) gehört (Zeile 14).

 

IO-Extensions

Unser Ziel ist es mit Hilfe der Erweiterungsmethoden einen Datei- oder Ordnerpfad (String) wie ein FileInfo-Object oder DirectoryInfo-Object zu behandeln.

 

Endung einer Datei ermitteln:
1: /// <summary>
2: /// Gibt die Endung einer Datei zurück
3: /// </summary>
4: /// <param name="__path">Pfad der Datei</param>
5: /// <returns>Endung ohne Punkt</returns>
6: public static string _Extenstion(this String __path)
7: {
8:     if (File.Exists(__path))
9:         return new FileInfo(__path).Extension.Substring(1);
10:  
11:     else
12:         throw new FileNotFoundException("Datei existiert nicht.");
13:  
14: }

Den Substring(1) mach ich hier, damit ich die Endung ohne Punkt bekomme. Es geht schneller und ist übersichtlicher den Punkt nachträglich hinzuzufügen als ihn zu entfernen. (Das nur mal so am Rande)

 

Größe einer Datei ermitteln
1: /// <summary>
2: /// Gibt die Dateigröße zurück
3: /// </summary>
4: /// <param name="__path">Pfad der Datei</param>
5: /// <returns>Dateigröße</returns>
6: public static long _FileSize(this String __path)
7: {
8:     if(File.Exists(__path))
9:         return new FileInfo(__path).Length;
10:  
11:  
12:     else
13:         throw new FileNotFoundException("Datei
        existiert nicht.");
14: }

Diese Methode könnte man noch so erweitern, dass die Größe (wie im Explorer) von Bytes in KiloByte, MegaByte und GigaByte umgerechnet und beschriftet wird.

 

Größe eines Ordners ermitteln

Hier müssen wir unterscheiden, ob nur die Größe des Ordners selbst oder auch mit allen Unterordnern berechnet werden soll.

1: /// <summary>
2: /// Gibt die Ordnergröße zurück
3: /// </summary>
4: /// <param name="__path">Pfad zum Ordner</param>
5: /// <returns>Ordnergröße</returns>
6: public static long _FolderSize(this String __path)
7: {
8:     return __path._FolderSize(false);
9: }
10:  
11:  
12: /// <summary>
13: /// Gibt die Ordnergröße zurück
14: /// </summary>
15: /// <param name="__path">Pfad zum Ordner</param>
16: /// <param name="__recursiv">Unterordner auch dazu zählen</param>
17: /// <returns>Ordnergröße</returns>
18: public static long _FolderSize(this String __path, bool __recursiv)
19: {
20:     if (Directory.Exists(__path))
21:     {
22:         if (__recursiv)
23:             return FolderSize(new DirectoryInfo(__path));
24:  
25:         else
26:         {
27:             long retValue = 0;
28:  
29:             foreach (FileInfo fi in new DirectoryInfo(__path).GetFiles())
30:                 retValue += fi.Length;
31:  
32:             return retValue;
33:         }
34:     }
35:     else
36:         throw new DirectoryNotFoundException("Ordner existiert nicht.");
37: }
38:  
39: /// <summary>
40: /// Ermittelt die Ordnergröße samt Unterordner
41: /// </summary>
42: /// <param name="__di">Ordner</param>
43: /// <returns>Größe</returns>
44: private static long FolderSize(DirectoryInfo __di)
45: {
46:     long retValue = 0;
47:  
48:     foreach (DirectoryInfo di in __di.GetDirectories())
49:         retValue += FolderSize(di);
50:  
51:     foreach (FileInfo fi in __di.GetFiles())
52:         retValue += fi.Length;
53:  
54:     return retValue;
55: }

Bei diesem Beispiel kann der genaue Beobachter erkennen, dass die Erweiterungsmethoden auch Parameter haben können und bei unterschiedlichen Parametern auch den selben Namen haben können (wie wir es bereits gewohn sind). Die Funktionsweise des rekursiven Aufrufes werde ich hier nicht erleutern. Solle doch jemand Schwierigkeiten im Verständnis haben, kann er mich gerne kontaktieren.

 

Überprüfen ob eine Datei/ein Ordner existiert
1: /// <summary>
2: /// Prüft ob eine Datei/Ordner mit dem Pfad existert
3: /// </summary>
4: /// <param name="__path">Pfad</param>
5: /// <returns>true/false</returns>
6: public static bool _Exists(this String __path)
7: {
8:     if (File.Exists(__path))
9:         return true;
10:  
11:     else if (Directory.Exists(__path))
12:         return true;
13:  
14:     else
15:         return false;
16: }

Die Methode könnten wir jeweils für Dateien und Ordner separat erstellen, ist ein meinen Augen aber nicht nötig.

 

Prüfen ob der Pfad ein Ordner oder eine Datei ist
1: public enum IOType { File, Directory, DontExist };
2:  
3: /// <summary>
4: /// Ermittelt ob der Pfad zu eine Datei oder zu einem Ordner zeigt
5: /// </summary>
6: /// <param name="__path">Pfad</param>
7: /// <returns>Datei/Ordner/Datei existiert nicht</returns>
8: public static IOType _Type(this String __path)
9: {
10:     if (File.Exists(__path))
11:         return IOType.File;
12:  
13:     else if (Directory.Exists(__path))
14:         return IOType.Directory;
15:  
16:     return IOType.DontExist;
17: }

Ich habe mich hierbei entschieden für den Rückgabewert eine eigene Enumeration zu erstellen. Könnte man auch handhaben wie man will. Diese Methode ist uns später noch nützlich.

 

Den Pfad (String) in ein File- oder DirectoryInfo konvertieren
1: /// <summary>
2: /// Erzeigt aus einem Pfad ein FileInfo
3: /// </summary>
4: /// <param name="__path">Pfad</param>
5: /// <returns>FileInfo</returns>
6: public static FileInfo _ConvertToFileInfo(this String __path)
7: {
8:     if (File.Exists(__path))
9:         return new FileInfo(__path);
10:  
11:     else
12:         throw new FileNotFoundException("Datei existiert nicht.");
13: }
14:  
15:  
16: /// <summary>
17: /// Erzeugt aus einem Pfad ein DirectoryInfo
18: /// </summary>
19: /// <param name="__path">Pfad</param>
20: /// <returns>DirectoryInfo</returns>
21: public static DirectoryInfo _ConvertToDirectoryInfo(this String __path)
22: {
23:     if (Directory.Exists(__path))
24:         return new DirectoryInfo(__path);
25:  
26:     else
27:         throw new DirectoryNotFoundException("Ordner
        existiert nicht.");
28: }

Diese zwei Methoden sind sinnvoll, falls wir als Parameter ein FileInfo- oder DirectoryInfoobject übergeben müssen.

 

Attribute von Dateien/Ordner auslesen
1: /// <summary>
2: /// Letzter Schreibzugriff auf den Pfad
3: /// </summary>
4: /// <param name="__path">Pfad</param>
5: /// <returns>Zeit</returns>
6: public static DateTime _LastWriteTime(this String __path)
7: {
8:     if (File.Exists(__path))
9:         return new FileInfo(__path).LastWriteTime;
10:  
11:     else if (Directory.Exists(__path))
12:         return new DirectoryInfo(__path).LastWriteTime;
13:  
14:     else
15:         throw new IOException("Pfad
        existiert nicht.");
16: }
17:  
18:  
19: /// <summary>
20: /// Letzter Lesezugriff auf den Pfad
21: /// </summary>
22: /// <param name="__path">Pfad</param>
23: /// <returns>Zeit</returns>
24: public static DateTime _LastAccessTime(this String __path)
25: {
26:     if (File.Exists(__path))
27:         return new FileInfo(__path).LastAccessTime;
28:  
29:     else if (Directory.Exists(__path))
30:         return new DirectoryInfo(__path).LastAccessTime;
31:  
32:     else
33:         throw new IOException("Pfad
        existiert nicht.");
34: }
35:  
36:  
37: /// <summary>
38: /// Zeit an dem die Datei/der Ordner erstellt wurde
39: /// </summary>
40: /// <param name="__path">Pfad</param>
41: /// <returns>Zeit</returns>
42: public static DateTime _CreationTime(this String __path)
43: {
44:     if (File.Exists(__path))
45:         return new FileInfo(__path).CreationTime;
46:  
47:     else if (Directory.Exists(__path))
48:         return new DirectoryInfo(__path).CreationTime;
49:  
50:     else
51:         throw new IOException("Pfad
        existiert nicht.");
52: }

Als Beispiel hab ich hier das Datum des Erstellens, der letzten Änderung und des letzten Zugriffs genommen.

 

Ordnerinhalt ermitteln
1: /// <summary>
2: /// Liste mit untergeordneten Dateien
3: /// </summary>
4: /// <param name="__pfad">Pfad des Ordners</param>
5: /// <returns>Liste</returns>
6: public static List<string> _ListFiles(this String __path)
7: {
8:     List<string> retValue = new List<string>();
9:  
10:     if (!Directory.Exists(__path))
11:         throw new DirectoryNotFoundException("Ordner
        existiert nicht.");
12:  
13:     foreach (FileInfo fi in new DirectoryInfo(__path).GetFiles())
14:         retValue.Add(fi.FullName);
15:  
16:     return retValue;
17: }
18:  
19:  
20: /// <summary>
21: /// Liste mit untergeordneten Ordner
22: /// </summary>
23: /// <param name="__pfad">Pfad des Ordners</param>
24: /// <returns>Liste</returns>
25: public static List<string> _ListDirectories(this String __path)
26: {
27:     List<string> retValue = new List<string>();
28:  
29:     if (!Directory.Exists(__path))
30:         throw new DirectoryNotFoundException("Ordner existiert nicht.");
31:  
32:     foreach (DirectoryInfo di in new DirectoryInfo(__path).GetDirectories())
33:         retValue.Add(di.FullName);
34:  
35:     return retValue;
36: }

Dateien und Unterordner eines Ordners werden ein eine Liste gefüllt. Wenn wir hier noch weiter denken, bemerken wir, dass wir für die einzelnen Inhalte der Liste wieder unsere Erweiterungsmethoden verwenden können.

 

Übergeordneter Ordner anzeigen
1: /// <summary>
2: /// Gibt den übergeordneten Ordner zurück
3: /// </summary>
4: /// <param name="__path">Ordner oder Datei</param>
5: /// <returns>übergeordneter Ordner</returns>
6: public static string _Parent(this String __path)
7: {
8:     if (__path._Exists())
9:     {
10:         if (__path._Type() == IOType.File)
11:             return __path._ConvertToFileInfo().DirectoryName;
12:  
13:         if (__path._Type() == IOType.Directory)
14:             return __path._ConvertToDirectoryInfo().Parent.FullName;
15:     }
16:  
17:     throw new IOException("Pfad
        existiert nicht.");
18:  
19: }

Will man sich einen Explorer basteln, ist es sehr von Vorteil schnell auf den übergeordneten zugreifen zu können.

 

Pfad umbenennen
1: /// <summary>
2: /// Benennt eine Datei/ein Ordner um
3: /// </summary>
4: /// <param name="__path">Ordner oder Datei</param>
5: /// <param name="__newName">neuer Name</param>
6: public static void _rename(this String __path, string __newName)
7: {
8:     if (__path._Exists())
9:     {
10:         try
11:         {
12:             if (__path._Type() == IOType.Directory)
13:                 new DirectoryInfo(__path).MoveTo(__path._Parent() + 
                    @"\" + __newName);
14:  
15:             if (__path._Type() == IOType.File)
16:                 new FileInfo(__path).MoveTo(__path._Parent() + @"\" +
                     __newName);
17:         }
18:         catch (IOException ex)
19:         {
20:             throw ex;
21:         }
22:     }
23:  
24:     else
25:         throw new IOException("Pfad existiert nicht.");
26: }

Auch Aktionen mit der Datei/dem Ordner selber, lassen sich durchführen. Hier will noch noch anmerken, dass es vielleicht von Vorteil ist, wenn man sich als Rückgabewert den neuen Pfad geben lässt. Somit kann man auch gleich den Pfad ändern.

1: string pfad = @"C:\AlterName.txt";
2: pfad = pfad._rename("neuerName.txt");

 

Datei kopieren
1: /// <summary>
2: /// Kopiert eine Datei an das angegebene Ziel
3: /// </summary>
4: /// <param name="__path">Quelle</param>
5: /// <param  name="__destination">Ziel (Ganzer Pfad verwenden: 
   /// C:\windows\system32\notepad.exe)</param>
6: public static void _FileCopy(this String __path, string __destination)
7: {
8:     if (__path._Exists())
9:     {
10:         if (__path._Type() == IOType.File)
11:             new FileInfo(__path).CopyTo(__destination);
12:     }
13:  
14:     else
15:         throw new FileNotFoundException("Datei
        existiert nicht.");
16: }

Auch in dieser Methode können wir erkennen, dass wir in der "Erweiterten Methode" auch andere "Erweiterte Methoden" aufrufen können. (Zeile 10)

 

Datei/Ordner löschen
1: /// <summary>
2: /// Löscht eine Datei oder einen Ordner samt Unterordnern
3: /// </summary>
4: /// <param name="__path">Datei/Ordner</param>
5: public static void _Delete(this String __path)
6: {
7:     if (__path._Exists())
8:     {
9:         try
10:         {
11:             if (__path._Type() == IOType.Directory)
12:                 new DirectoryInfo(__path).Delete(true);
13:  
14:             if (__path._Type() == IOType.File)
15:                 new FileInfo(__path).Delete();
16:         }
17:         catch (Exception ex)
18:         {
19:             throw ex;
20:         }
21:     }
22:  
23:     else
24:         throw new IOException("Pfad existiert nicht.");
25: }

 

Schlusswort

Ich hoffe dieser Artikel ist euch eine Hilfe mit dem Umgang von Dateien und Ordner. Es lassen sich im IO-Bereich noch viele weitere Methoden hinzufügen, die je nach Anwendung eine große Arbeitserleicherung sein können. Diese Muster lässt sich auch auf andere Einsatzmöglichkeiten anwenden.

Falls ihr selber in diese Richtung etwas schreibt, wär ich sehr interessiert daran, eure Arbeiten zu begutachten.

 

Den kompletten Quelltext gibts hier.

von flachzange, 31.07.2008 zugeordnet zu C# .

Kommentare

Es sind noch keine Kommentare vorhanden.

Eigener Kommentar

Sie müssen angemeldet sein, um ein Kommentar zu erstellen.
  • Schwierigkeit: Einsteiger
  • Views: 1637
  • Zur Druckversion
  • Artikel von flachzange

Kick it on dotnet-kicks.de

Artikel

Autor

Kick it!

Wenn ihnen dieser Artikel gefällt, bitte "kicken" sie ihn.

WPF Forum | ASP.NET Forum | ASP.NET MVC Forum | Silverlight Forum | Windows Phone 7 Forum | SharePoint Forum | Dotnet Jobs | Dotnet Termine | Developer Blogs | Dotnet News

Das Team | Regeln | Impressum