code it

Martins Tech Blog

Ermittlung der größten Datei(en) in einer Ordnerstruktur

Wie kann man ausgehend von einem Ordner von allen Dateien - auch die die in Unterordnern sind - die größte bzw. die größten ermitteln? 

Das Ziel ist ganz klar - es wird aus der Ordnerstruktur das FileInfo-Objekt benötigt, dessen Eigenschaft Length am größten ist. Um an diese Objekte zu kommen, gibt es zum einen die Möglichkeit, rekursiv durch alle Unterordner gehen und für alle Dateien ein solches Objekt zu erzeugen und sich die relevanten Objekte zu speichern. Eine andere Möglichkeit ist, per Directory.GetFiles an die Dateipfade und darüber diese FileInfo-Objekte zu instanziieren:

// define the root
const string rootPath = @"C:\Program Files\Microsoft SQL Server";

// check if the directory exists
if (!Directory.Exists(rootPath))
    throw new DirectoryNotFoundException();

// get all file names in the directory
// warning: may throw System.UnauthorizedAccessException
string[] fileNames = Directory.GetFiles(rootPath, "*.*", SearchOption.AllDirectories);

// get all FileInfo objects from file names
var files = fileNames.Select(fileName => new FileInfo(fileName));

// query the largest file
FileInfo largestFile = (from file in files
                        orderby file.Length descending
                        select file).First();

// query the top 10 largest files
FileInfo[] topTenLargestFiles = (from file in files
                               orderby file.Length descending
                               select file).Take(10).ToArray();

Vorteil dieser Methode: Der Code ist kurz und übersichtlich. Aber es gibt auch mindestens einen Nachteil: Besteht nach Code Access Policy kein Zugriff auf eine der abgefragten Dateien oder Ordner, so wirft Directory.GetFiles eine System.UnauthorizedAccessException und bricht ohne Ergebnis ab. 

Die Selektion der größten Datei(en) selbst ist dann, wie gezeigt, sehr leicht mit LINQ zu realisieren.

DateTime.Parse und UTC

Manchmal lässte es sich ganz einfach nicht vermeiden, dass man Datumswerte aus einem Text erzeugen muss. Und aus genau diesem Grund hab ich mich nun auch mal etwas intensiver mit dem Verhalten von DateTime.Parse beschäftigt.

Ausgangspunkt ist folgender Text:

string dateTimeAsText = "2009-08-18T13:36:02.000Z";

Wie man gut erkennen kann, repräsentiert der Text ein Datum mit Zeit in UTC gemäß ISO 8601. Nun kann es ja nicht so schwer sein, diesen Wert als DateTime in UTC zu ermitteln, möchte man meinen - schließlich gibt es ja DateTime.Parse:

string dateTimeAsText = "2009-08-18T13:36:02.000Z";

DateTime dateTimeValue = DateTime.Parse(dateTimeAsText, CultureInfo.InvariantCulture);

Bei der Überprüfung des Wertes fällt auf, dass der erzeugte Wert mitnichten der 18.08.2009 13:36:02 ist, sondern dass direkt eine Umwandlung in die lokale Zeit des ausführenden Systems durchgeführt wird. Erwartet hätte ich, dass der Wert direkt übernommen wird und das DateTimeKind auf DateTimeKind.Utc oder zumindest auf DateTimeKind.Unspecified steht.

Besonders bei Webanwendungen, die nicht in der gleichen Zeitzone laufen in der sich der Client befindet, ist dieses Verhalten eher hinderlich. Hier ist in der Logikschicht und der Datenschicht UTC in meinen Augen die sinnvollste Möglichkeit mit Datumswerten umzugehen und erst in der Präsentationsschicht die Umwandlung in die jeweilige Benutzerzeit durchzuführen.

Erste Möglichkeit ist nun, nach jedem Aufruf der Parse-Methode auf dem entstehenden Wert die Methode ToUniversalTime aufzurufen. Hier könnte man aber erwarten, dass es irgendwie schon eine Out-of-the-box-Lösung gibt, die das gleiche Ergebnis bringt. 

Geht nicht? Geht doch. DateTime.Parse hat eine Überladung mit 3 Parametern:

string dateTimeAsText = "2009-08-18T13:36:02.000Z";
DateTime dateTimeValue = DateTime.Parse(dateTimeAsText, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

Der relevante Wert ist DateTimeStyles.AdjustToUniversal. Dieser legt fest, dass der Ergebniswert ein DateTime vom Typ DateTimeKind.Utc sein soll.

"Checked out by somesone else or in another place"... aber wer und wo?

Bei der Arbeit mit dem TFS ist mir aufgefallen, dass an einigen Dateien der Status "Checked out by somesone else or in another place" gesetzt ist. 

Zum einen wird man aus dieser Nachricht nicht viel schlauer, zum anderen erscheint sie manchmal auch dann, wenn man allein an einem Projekt arbeitet.

Der erste der genannten Fälle ist ein Bug im TFS - Dateien, für die ein Shelveset existiert werden fälschlicherweise mit diesem Status angezeigt.

Ob eine Datei wirklich von jemand anders angecheckt ist, kann man über das Kommandozeilentool tf.exe erfahren. Dazu öffnet man den Visual Studio 2008 Command Prompt. Der Befehl "tf status $/project /user:* /recursive" zeigt in einer Übersicht mit den Spalten File name, Change, User und Local path alle augechecken Dateien aller Nutzer des angegebenen Projektes an:

 

Treffen der .NET Usergroup Dresden

Das nächste Treffen der .NET Usergroup Dresden findet am 09.09. im Gebäude der Communardo Software GmbH statt. Beginn ist wie immer 18:00 Uhr. Folgende Themen gibt es an diesem Abend:
  • Silverlight 2.0 im Unternehmenseinsatz - Integration eines Prozess-Editors à la Visio in SharePoint (Kai-Uwe Gärtner)
  • Lambda Expressions & LINQ Teil 2 (Oliver Guhr)
Weitere Informationen zum Termin und einen Link zur Anmeldeliste findet man auf der Seite der .NET Usergroup.

IndexOf und LastIndexOf erweitern

IndexOf und LastIndexOf sind sehr mächtige Funktionen. Sie ermöglichen es, die erste bzw. die letzte Position eines Zeichens oder einer Zeichenkette innerhalb einer anderen Zeichenkette zu ermitteln. Leider ist out-of-the-box keine Implementierung vorgesehen, die das zweite Vorkommen oder das vorletzte Vorkommen sucht.

Eine mögliche Lösung kann man sich aber leicht selbst mit Hilfe von Extension-Methods erzeugen:

public static class StringExtensionMethods
{
    public static int IndexOf(this string input, string value, int startIndex, int count, int occurrence, StringComparison comparisonType)
    {
        int retval = startIndex;
        for (int i = 0; i < occurrence; i++)
        {
            retval = input.IndexOf(value, retval + 1, comparisonType);
        }
        return (retval);
    }

    public static int LastIndexOf(this string input, string value, int startIndex, int count, int occurrence, StringComparison comparisonType)
    {
        int retval = startIndex + 1;
        for (int i = 0; i < occurrence; i++)
        {
            retval = input.LastIndexOf(value, retval - 1, comparisonType);
        }
        return (retval);
    }
}

Der zusätzliche Parameter occurrence ermöglicht es, zu spezifizieren, das wievielte Ergebnis man als Rückgabewert bekommen möchte.

22. Treffen der PASS-Regionalgruppe Sachsen

Am 14.08. hat sich die Regionalgruppe Sachsen der PASS zum 22. Mal getroffen. Hier hatte ich die Gelegenheit, die Basics des in SQL-Server 2008 neuen Datentyps HierarchyId zu erklären und an ein paar Beispielen zu verdeutlichen. In der anschließenden Diskussionsrunde wurden dann im gemeinsamen Live-Coding die noch offenen Fragen geklärt.

Die Folien und die Beispiele kann man auf der Seite der PASS Regionalgruppe Dresden herunterladen.

Mit LINQ To Objects jedes n-te Element selektieren

Besonders nach string.Split()-Aufrufen ist es mir schon häufiger untergekommen, dass ich nur jedes 2. Element aus einem Ergebnis-Array bekommen wollte. Meist läuft man dann einfach mit einer for-each-Schleife durch das Array und nimmt sich die passenden Elemente.

Mit Hilfe der Extension-Methods, die Linq bietet, kann man die gleiche Funktionalität auch erreichen. Im folgenden Beispiel wird aus dem Array jedes 2. Element herausgelöst:

string[] values = new [] { "a", "b", "c", "d" };
var result = values.Select(value => value)
                   .Where((value, index) => (index+1) % 2 == 0);

.NET Open Space 2009 Leipzig

Die besten Gespräche hat man fernab von einer festgelegten Agenda, bei einem Kaffee und beim "du". Hier gibt es keine Rollenaufteilung in Sprecher / Zuhörer, Entwickler / Administrator, Softwareentwickler / Projektmanager usw. und die Themen finden sich vor Ort ganz von selbst. Das ist die Idee vom .NET Open Space: Alle sind gleich! Auch die Organisatoren halten sich im Hintergrund und moderieren nur wenig. Verantwortliche der Themenfelder ALT.NET, Clean Code Developer, Mobile Computing, Soft Skills, User Interfaces / User Experience sorgen mit Einladungen für viele Teilnehmer. Welche Inhalte in den einzelnen Themenfeldern und in welcher Form, z. B. als Vortrag oder in der Runde, bearbeitet werden, wird vor Ort bestimmt. Das nennt sich "Open Space". Die Teilnahme ist kostenlos. Erfahrungsaustausch ist das A und O und steht im Vordergrund. Die Sprache beim .NET Open Space 2009 ist Deutsch. Mehr gibt's nicht zu sagen. Die "Unkonferenz", die sich auf Erfahrungsaustausch konzentriert, läuft am 17./18.10.2009. Mehr dazu unter http://netopenspace.de/2009.