Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Directory Browsing a la .NET

Geschrieben von: Christoph Wille
Kategorie: ASP.NET

This printed page brought to you by AlphaSierraPapa

Aus den "guten alten Zeiten" des ASP Programmierens dürfte sehr vielen das FileSystemObject Objekt in Erinnerung sein. Es erlaubt Zugriff auf das Dateisystem für Lesen, Schreiben und Directory Browsing. Allerdings ist Objektmodell alles andere als optimal, und bei binären Dateien ist das Ende der Fahnenstange erreicht, bevor man am Ziel ist - es geht schlicht und ergreifend nicht.

Auch sonst gibt es einige Funktionen und Eigenschaften, die ich sehr gerne gehabt hätte. Es scheint so, als würden diese Wünsche mit den .NET Framework Klassen im System.IO Namespace in Erfüllung gehen. Die Dateiverarbeitung war nie einfacher, und vor allem nie leistungsfähiger.

Für diesen Artikel habe ich einen Teil der Dateiverarbeitung herausgepickt: das Auflisten von Dateien und Ordnern. Ich habe einige nette Scripts gebastelt, die man später in eigenen Applikationen einsetzen kann. Weitere Artikel werden sich mit dem Lesen und Schreiben von Dateien befassen.

Voraussetzung um den Sourcecode dieses Artikels verwenden zu können ist eine Installation des Microsoft .NET Framework SDK's auf einem Webserver. Weiters setze ich voraus, daß der Leser die Programmiersprache C# zu einem gewissen Grad beherrscht - es finden sich etliche Artikel auf diesem Server, um das notwendige Wissen zu erlernen.

Laufwerke aufzählen

Das Erste, was wir herausfinden sollten ist, welche Laufwerke eigentlich so am Rechner für uns zum Herumstöbern verfügbar sind (listdrives.aspx):

<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string[] achDrives = Directory.GetLogicalDrives();
int nNumOfDrives = achDrives.Length;

Response.Write("<ul>");
for (int i=0; i < nNumOfDrives; i++)
{
 Response.Write("<li><a href=\"listdir.aspx?dir=");
 Response.Write(Server.UrlEncode(achDrives[i]));
 Response.Write("\">" + achDrives[i]);
 Response.Write("</a><br>");
}
Response.Write("</ul>");
%>

Im System.IO Namespace (mit der @Import Namespace Anweisung eingebunden) gibt es eine Klasse namens Directory. Dieses repräsentiert Funktionalitäten die man mit einem Verzeichnis brauchen kann, und die Klasse enthält auch die statische (ohne Objektinstanz aufrufbare) Methode GetLogicalDrives. Diese liefert uns ein Array von Strings, die die Laufwerksbuchstaben enthalten.

Natürlich habe ich es nicht bei einer einfachen Auflistung der über GetLogicalDrives erhaltenen Laufwerke belassen - ich habe gleich einen Link auf eine weiterführende Seite eingebaut, die dann Aufschluß über den Inhalt des Root-Verzeichnisses des Laufwerks gibt.

Verzeichnisse und Dateien auflisten

Jetzt sind wir in einem Verzeichnis. Was interessiert uns dort? Zum Beispiel die Unterverzeichnisse und Dateien, als auch Eigenschaften des Verzeichnisses selbst (Erstellungsdatum, etc). Das folgende Sourcodelisting der Datei listdir.aspx zeigt, wie man die geforderte Funktionalität implementieren könnte:

<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string strDir2List = Request.QueryString.Get("dir");
DirectoryInfo thisOne = null;

try
{
  thisOne = new DirectoryInfo(strDir2List);
  // Auslesen der Eigenschaften der Verzeichnisses
  Response.Write("<p>Erzeugung: " + 
     thisOne.CreationTime.ToString() + "</p>");

  DirectoryInfo[] subDirectories = thisOne.GetDirectories();
  Response.Write("<ul>");
  for (int i=0; i < subDirectories.Length; i++)
  {
    Response.Write("<li><a href=\"listdir.aspx?dir=");
    Response.Write(Server.UrlEncode(subDirectories[i].FullName));
    Response.Write("\">" + subDirectories[i].Name);
    Response.Write("</a><br>");
  }
  Response.Write("</ul>");
  
  FileInfo[] theFiles = thisOne.GetFiles();
  Response.Write("<ul>");
  for (int i=0; i < theFiles.Length; i++)
  {
    Response.Write("<li><a href=\"showfile.aspx?file=");
    Response.Write(Server.UrlEncode(theFiles[i].FullName));
    Response.Write("\">" + theFiles[i].Name);
    Response.Write("</a><br>");
  }
  Response.Write("</ul>");
}
catch (Exception e)
{
  Response.Write("Zugriff nicht möglich, Fehler: <i>");
  Response.Write(e.ToString() + "</i>");
  Response.End();
}
%>

Das Auslesen der Verzeichnisse funktioniert mittels der GetDirectories Methode, die mir ein Array von DirectoryInfo Objekten liefert, mit denen ich dann meine gewünschte Funktionalität aufbauen kann (zB wie hier ein weiterer Link für den Drill-Down). Gleiches gilt für die GetFiles Methode, die ein Array von FileInfo Objekten liefert. Mehr zu diesem in der nächsten Sektion.

Wozu brauche ich bitte schön das Exception Handling? Nun, es könnte ja sein, daß ich auf etwas zugreife, wo ich nicht hingreifen darf, und dann bekommt man eine auf die Finger (dieser Fall dürfte auch dem Real-Life bekannt sein...). Im Ernst: es könnten zum Beispiel die NTFS Rechte für den aktuellen Benutzer nicht ausreichend sein (Listen verboten).

Dateiinformationen ausgeben

Jetzt sind wir auf der Dateiebene. Natürlich hat eine Datei eine Menge von Eigenschaften, und das folgende Beispiel showfile.aspx präsentiert nur eine Untermenge. Ein Blick in die Dokumentation enthüllt den Rest dessen, was ich zur Kürzung des Scripts ausgelassen habe.

<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<html>
<head><title>File Info</title></head>
<body>
<%
string strFile2Show = Request.QueryString.Get("file");
FileInfo thisOne = new FileInfo(strFile2Show);
%>
<table>
<tr><td>Name:</td><td><%=thisOne.Name%></td></tr>
<tr><td>Pfad:</td><td><%=thisOne.FullName%></td></tr>
<tr><td>Verzeichnis:</td><td><%=thisOne.DirectoryName%></td></tr>
<tr>
  <td>Erstellung:</td>
  <td><%=thisOne.CreationTime.ToString()%></td>
</tr>
<tr>
  <td>Länge:</td>
  <td><%=thisOne.Length.ToString()%> Bytes</td>
</tr>
<tr>
  <td>Letzter Zugriff:</td>
  <td><%=thisOne.LastAccessTime.ToString()%></td>
</tr>
<tr>
  <td>Letzte Modifikation:</td>
  <td><%=thisOne.LastWriteTime.ToString()%></td>
</tr>
</table>

<%
StreamReader theReader = thisOne.OpenText();
char[] theBuffer = new char[255];
int nRead = theReader.ReadBlock(theBuffer, 0, 255);
Response.Write("<pre>");
Response.Write(Server.HtmlEncode(new String(theBuffer,0,nRead)));
Response.Write("</pre>");
%>

</body>
</html>

Am Ende des Scripts habe ich einen kurzen Ausflug in Richtung Dateiauslesen unternommen, um zu demonstrieren, wie einfach das ist. Zuerst öffne ich ein StreamReader Objekt, lege einen Puffer an, fülle den Puffer mit der ReadBlock Methode und gebe den eingelesenen Block dann HTML-encoded mit an den Client aus. Und schon hat man eine kleine "Dateivorschau". Nicht gerade weltbewegend, aber es demonstriert bereits, wie einfach auch das Arbeiten mit den Inhalten von Dateien ist.

Rekursives Auflisten eines Verzeichnisses

Zu guter Letzt habe ich noch ein kleines Programm zum Erzeugen eines Verzeichnisbaums in Petto. Wie die Überschrift schon verrät, wird der Baum rekursiv erzeugt - man braucht also eine Funktion, die rekursiv aufgerufen werden kann. Im Beispiel recursivelisting.aspx heißt diese RecursiveDump:

<% @Page Language="C#" %>
<% @Import Namespace="System.IO" %>
<%
string strDir2List = Request.QueryString.Get("dir");
DirectoryInfo thisOne = new DirectoryInfo(strDir2List);

Response.Write("<pre>");
RecursiveDump(thisOne, 0);
Response.Write("</pre>");
%>

<script language="C#" runat="server">
void RecursiveDump(DirectoryInfo theDir, int nLevel)
{
  DirectoryInfo[] subDirectories = theDir.GetDirectories();
  for (int i=0; i < subDirectories.Length; i++)
  {
    Response.Write(new String(' ',nLevel));
    Response.Write(subDirectories[i].Name + "\r\n");
    RecursiveDump(subDirectories[i], nLevel+1);
  }
}
</script>

Wie immer habe ich es mir besonders einfach gemacht, und verwende einfach Leerzeichen um den Baum zu generieren. Damit man's in HTML auch sieht, muß man daher ein <PRE> Tag verwenden - sonst werden die Leerzeichen geschluckt.

Die Funktion selbst hat 2 Parameter: ein DirectoryInfo Objekt, und eine Integervariable, die die aktuelle Ebene bezeichnet. Es werden für die aktuelle Ebene die Unterverzeichnisse ausgelesen (mit GetDirectories), und dann mit einer for Schleife ausgegeben. Für jedes DirectoryInfo Objekt wird die Funktion RecursiveDump aufgerufen, und die Ebene um 1 erhöht.

Das Ergebnis kann dann so aussehen (Achtung: wenn man ein ganzes Laufwerk aufbauen läßt, so kann dies schon einige Zeit in Anspruch nehmen!):

Schlußbemerkung:

In diesem Artikel habe ich drei Objekte aus dem System.IO Namespace präsentiert: Directory, DirectoryInfo und FileInfo. Obwohl ich sie "nur" zum Ausgeben einfacher Verzeichnis- und Dateiinformationen verwendet habe, sind diese Objekte die Basis zur Dateiverarbeitung wie Lesen und Schreiben. Dazu aber mehr in einem späteren Artikel.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20000804.zip

Verwandte Artikel

Dateien lesen in ASP.NET
http:/www.aspheute.com/artikel/20000929.htm
Dateien umbenennen
http:/www.aspheute.com/artikel/20020409.htm
Ein Touch-Utility in C#
http:/www.aspheute.com/artikel/20020226.htm
Eine Klasse für sich - die .NET Zip Library
http:/www.aspheute.com/artikel/20011115.htm
Exception Handling in C#
http:/www.aspheute.com/artikel/20000724.htm
Online File Management System mit ASP.NET und C# - Teil 1
http:/www.aspheute.com/artikel/20021031.htm
Online File Management System mit ASP.NET und C# - Teil 2
http:/www.aspheute.com/artikel/20021105.htm
Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm
Verzeichnisbäume rekursiv generieren
http:/www.aspheute.com/artikel/20011016.htm

Links zu anderen Sites

Die aspDEdotnet Diskussionsliste
http://www.dotnetgerman.com/listen/aspDEdotnet.asp
Download ASP.NET
http://www.dotnetgerman.com/links/dl_aspnet.asp

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.