Freigeben über


Formate von Dateipfaden unter Windows-Systemen

Elemente vieler Typen im System.IO Namespace enthalten einen path Parameter, mit dem Sie einen absoluten oder relativen Pfad zu einer Dateisystemressource angeben können. Dieser Pfad wird dann an Windows-Dateisystem-APIs übergeben. In diesem Thema werden die Formate für Dateipfade erläutert, die Sie auf Windows-Systemen verwenden können.

Herkömmliche DOS-Pfade

Ein Standard-DOS-Pfad kann aus drei Komponenten bestehen:

  • Ein Volume oder Laufwerkbuchstabe gefolgt von dem entsprechenden Trennzeichen (:).
  • Ein Verzeichnisname. Das Verzeichnistrennzeichen trennt Unterverzeichnisse innerhalb der geschachtelten Verzeichnishierarchie.
  • Optionaler Dateiname. Das Verzeichnistrennzeichen trennt den Dateipfad und den Dateinamen.

Wenn alle drei Komponenten vorhanden sind, ist der Pfad absolut. Wenn kein Volume oder Laufwerkbuchstabe angegeben ist und der Name des Verzeichnisses mit dem Verzeichnistrennzeichen beginnt, ist der Pfad relativ zum Stamm des aktuellen Laufwerks. Andernfalls ist der Pfad relativ zum aktuellen Verzeichnis. In der folgenden Tabelle sind einige mögliche Verzeichnis- und Dateipfade aufgeführt.

Pfad BESCHREIBUNG
C:\Documents\Newsletters\Summer2018.pdf Ein absoluter Dateipfad vom Stamm des Laufwerks C:
\Program Files\Custom Utilities\StringFinder.exe Ein relativer Pfad aus dem Stamm des aktuellen Laufwerks.
2018\January.xlsx Ein relativer Pfad zu einer Datei in einem Unterverzeichnis des aktuellen Verzeichnisses.
..\Publications\TravelBrochure.pdf Ein relativer Pfad zu einer Datei in einem Verzeichnis, vom aktuellen Verzeichnis aus.
C:\Projects\apilibrary\apilibrary.sln Ein absoluter Pfad zu einer Datei vom Stammverzeichnis des Laufwerks C:.
C:Projects\apilibrary\apilibrary.sln Ein relativer Pfad vom aktuellen Verzeichnis des Laufwerks C:

Von Bedeutung

Beachten Sie den Unterschied zwischen den letzten beiden Pfaden. Beide geben den optionalen Volumebezeichner (in beiden Fällen C:) an. Der erste beginnt jedoch im Gegensatz zum zweiten mit dem Stamm des angegebenen Volumes. Daher ist der erste ein absoluter Pfad aus dem Stammverzeichnis des Laufwerks C:, während die zweite ein relativer Pfad aus dem aktuellen Verzeichnis des Laufwerks C:ist. Verwendung des zweiten Formulars, wenn die erste vorgesehen ist, ist eine häufige Quelle von Fehlern, die Windows-Dateipfade umfassen.

Sie können ermitteln, ob ein Dateipfad vollständig qualifiziert ist (d. h., wenn der Pfad unabhängig vom aktuellen Verzeichnis ist und sich nicht ändert, wenn sich das aktuelle Verzeichnis ändert), indem Sie die Path.IsPathFullyQualified Methode aufrufen. Beachten Sie, dass ein solcher Pfad relative Verzeichnissegmente (. und ..) enthalten kann und trotzdem vollqualifiziert sein kann, wenn der aufgelöste Pfad immer auf denselben Speicherort verweist.

Im folgenden Beispiel wird der Unterschied zwischen absoluten und relativen Pfaden veranschaulicht. Es wird davon ausgegangen, dass das Verzeichnis D:\FY2018\ existiert und dass Sie vor dem Ausführen des Beispiels kein aktuelles Verzeichnis in der Eingabeaufforderung für D:\ festgelegt haben.

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

public class Example2
{
    public static void Main(string[] args)
    {
        Console.WriteLine($"Current directory is '{Environment.CurrentDirectory}'");
        Console.WriteLine("Setting current directory to 'C:\\'");

        Directory.SetCurrentDirectory(@"C:\");
        string path = Path.GetFullPath(@"D:\FY2018");
        Console.WriteLine($"'D:\\FY2018' resolves to {path}");
        path = Path.GetFullPath(@"D:FY2018");
        Console.WriteLine($"'D:FY2018' resolves to {path}");

        Console.WriteLine("Setting current directory to 'D:\\Docs'");
        Directory.SetCurrentDirectory(@"D:\Docs");

        path = Path.GetFullPath(@"D:\FY2018");
        Console.WriteLine($"'D:\\FY2018' resolves to {path}");
        path = Path.GetFullPath(@"D:FY2018");

        // This will be "D:\Docs\FY2018" as it happens to match the drive of the current directory
        Console.WriteLine($"'D:FY2018' resolves to {path}");

        Console.WriteLine("Setting current directory to 'C:\\'");
        Directory.SetCurrentDirectory(@"C:\");

        path = Path.GetFullPath(@"D:\FY2018");
        Console.WriteLine($"'D:\\FY2018' resolves to {path}");

        // This will be either "D:\FY2018" or "D:\FY2018\FY2018" in the subprocess. In the sub process,
        // the command prompt set the current directory before launch of our application, which
        // sets a hidden environment variable that is considered.
        path = Path.GetFullPath(@"D:FY2018");
        Console.WriteLine($"'D:FY2018' resolves to {path}");

        if (args.Length < 1)
        {
            Console.WriteLine(@"Launching again, after setting current directory to D:\FY2018");
            Uri currentExe = new(Assembly.GetExecutingAssembly().Location, UriKind.Absolute);
            string commandLine = $"/C cd D:\\FY2018 & \"{currentExe.LocalPath}\" stop";
            ProcessStartInfo psi = new("cmd", commandLine); ;
            Process.Start(psi).WaitForExit();

            Console.WriteLine("Sub process returned:");
            path = Path.GetFullPath(@"D:\FY2018");
            Console.WriteLine($"'D:\\FY2018' resolves to {path}");
            path = Path.GetFullPath(@"D:FY2018");
            Console.WriteLine($"'D:FY2018' resolves to {path}");
        }
        Console.WriteLine("Press any key to continue... ");
        Console.ReadKey();
    }
}
// The example displays the following output:
//      Current directory is 'C:\Programs\file-paths'
//      Setting current directory to 'C:\'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to d:\FY2018
//      Setting current directory to 'D:\Docs'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to D:\Docs\FY2018
//      Setting current directory to 'C:\'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to d:\FY2018
//      Launching again, after setting current directory to D:\FY2018
//      Sub process returned:
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to d:\FY2018
// The subprocess displays the following output:
//      Current directory is 'C:\'
//      Setting current directory to 'C:\'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to D:\FY2018\FY2018
//      Setting current directory to 'D:\Docs'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to D:\Docs\FY2018
//      Setting current directory to 'C:\'
//      'D:\FY2018' resolves to D:\FY2018
//      'D:FY2018' resolves to D:\FY2018\FY2018
Imports System.IO
Imports System.Reflection

Public Module Example2

    Public Sub Main(args() As String)
        Console.WriteLine($"Current directory is '{Environment.CurrentDirectory}'")
        Console.WriteLine("Setting current directory to 'C:\'")
        Directory.SetCurrentDirectory("C:\")

        Dim filePath As String = Path.GetFullPath("D:\FY2018")
        Console.WriteLine($"'D:\\FY2018' resolves to {filePath}")
        filePath = Path.GetFullPath("D:FY2018")
        Console.WriteLine($"'D:FY2018' resolves to {filePath}")

        Console.WriteLine("Setting current directory to 'D:\\Docs'")
        Directory.SetCurrentDirectory("D:\Docs")

        filePath = Path.GetFullPath("D:\FY2018")
        Console.WriteLine($"'D:\\FY2018' resolves to {filePath}")
        filePath = Path.GetFullPath("D:FY2018")

        ' This will be "D:\Docs\FY2018" as it happens to match the drive of the current directory
        Console.WriteLine($"'D:FY2018' resolves to {filePath}")

        Console.WriteLine("Setting current directory to 'C:\\'")
        Directory.SetCurrentDirectory("C:\")

        filePath = Path.GetFullPath("D:\FY2018")
        Console.WriteLine($"'D:\\FY2018' resolves to {filePath}")

        ' This will be either "D:\FY2018" or "D:\FY2018\FY2018" in the subprocess. In the sub process,
        ' the command prompt set the current directory before launch of our application, which
        ' sets a hidden environment variable that is considered.
        filePath = Path.GetFullPath("D:FY2018")
        Console.WriteLine($"'D:FY2018' resolves to {filePath}")

        If args.Length < 1 Then
            Console.WriteLine("Launching again, after setting current directory to D:\FY2018")
            Dim currentExe As New Uri(Assembly.GetExecutingAssembly().GetName().CodeBase, UriKind.Absolute)
            Dim commandLine As String = $"/C cd D:\FY2018 & ""{currentExe.LocalPath}"" stop"
            Dim psi As New ProcessStartInfo("cmd", commandLine)
            Process.Start(psi).WaitForExit()

            Console.WriteLine("Sub process returned:")
            filePath = Path.GetFullPath("D:\FY2018")
            Console.WriteLine($"'D:\\FY2018' resolves to {filePath}")
            filePath = Path.GetFullPath("D:FY2018")
            Console.WriteLine($"'D:FY2018' resolves to {filePath}")
        End If
        Console.WriteLine("Press any key to continue... ")
        Console.ReadKey()
    End Sub
End Module
' The example displays the following output:
'      Current directory is 'C:\Programs\file-paths'
'      Setting current directory to 'C:\'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to d:\FY2018
'      Setting current directory to 'D:\Docs'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to D:\Docs\FY2018
'      Setting current directory to 'C:\'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to d:\FY2018
'      Launching again, after setting current directory to D:\FY2018
'      Sub process returned:
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to d:\FY2018
' The subprocess displays the following output:
'      Current directory is 'C:\'
'      Setting current directory to 'C:\'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to D:\FY2018\FY2018
'      Setting current directory to 'D:\Docs'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to D:\Docs\FY2018
'      Setting current directory to 'C:\'
'      'D:\FY2018' resolves to D:\FY2018
'      'D:FY2018' resolves to D:\FY2018\FY2018

UNC-Pfade

UnC-Pfade (Universal Naming Convention), die für den Zugriff auf Netzwerkressourcen verwendet werden, weisen das folgende Format auf:

  • Ein Server- oder Hostname, dem \\ vorangestellt ist. Der Servername kann ein NetBIOS-Computername oder eine IP/FQDN-Adresse sein (IPv4 sowie v6 werden unterstützt).
  • Ein Freigabename, der durch \ vom Hostnamen getrennt ist. Gemeinsam bilden der Server- und Freigabename das Volume.
  • Ein Verzeichnisname. Das Verzeichnistrennzeichen trennt Unterverzeichnisse innerhalb der geschachtelten Verzeichnishierarchie.
  • Optionaler Dateiname. Das Verzeichnistrennzeichen trennt den Dateipfad und den Dateinamen.

Im Folgenden sind einige Beispiele für UNC-Pfade aufgeführt:

Pfad BESCHREIBUNG
\\system07\C$\ Das Stammverzeichnis des Laufwerks C: auf system07
\\Server2\Share\Test\Foo.txt Die Datei Foo.txt im Testverzeichnis des Volumes \\Server2\Share

UNC-Pfade müssen immer absolut sein. Sie können relative Verzeichnissegmente (. und ..) enthalten, aber diese müssen Teil eines vollqualifizierten Pfads sein. Sie können relative Pfade nur verwenden, indem Sie einen UNC-Pfad zu einem Laufwerkbuchstaben zuordnen.

DOS-Gerätepfade

Das Windows-Betriebssystem verfügt über ein einheitliches Objektmodell, das auf alle Ressourcen verweist, einschließlich Dateien. Auf diese Objektpfade kann über das Konsolenfenster zugegriffen werden und der Win32-Ebene über einen speziellen Ordner symbolischer Verknüpfungen verfügbar gemacht werden, denen ältere DOS- und UNC-Pfade zugeordnet sind. Der Zugriff auf diesen speziellen Ordner erfolgt über die DOS-Gerätepfadsyntax, die einer der Folgenden entspricht:

\\.\C:\Test\Foo.txt \\?\C:\Test\Foo.txt

Zusätzlich zum Identifizieren eines Laufwerks anhand des Laufwerkbuchstabens können Sie ein Volume mithilfe des Volume-GUID identifizieren. Dies hat die Form:

\\.\Volume{b75e2c83-0000-0000-0000-602f00000000}\Test\Foo.txt \\?\Volume{b75e2c83-0000-0000-0000-602f00000000}\Test\Foo.txt

Hinweis

Die DOS-Gerätepfadsyntax wird für .NET-Implementierungen unterstützt, die unter Windows ausgeführt werden, beginnend mit .NET Core 1.1 und .NET Framework 4.6.2.

Der DOS-Gerätepfad besteht aus den folgenden Komponenten:

  • Der Gerätepfadbezeichner (\\.\ oder \\?\), der den Pfad als DOS-Gerätepfad identifiziert.

    Hinweis

    Dies \\?\ wird ab Version 4.6.2 in allen Versionen von .NET Core und .NET 5+ und .NET Framework unterstützt.

  • Eine symbolische Verknüpfung mit dem "realen" Geräteobjekt (C: im Fall eines Laufwerknamens oder Volume{b75e2c83-0000-0000-0000-60000-602f0000000} im Fall einer Volume-GUID).

    Das erste Segment des DOS-Gerätepfads, nachdem der Gerätepfadbezeichner das Volume oder Laufwerk identifiziert. (Beispiel: \\?\C:\ und \\.\BootPartition\.)

    Es gibt einen bestimmten Link für UNCs, der, nicht überraschend, UNC genannt wird. Beispiel:

    \\.\UNC\Server\Share\Test\Foo.txt \\?\UNC\Server\Share\Test\Foo.txt

    Bei Geräte-UNCs bildet der Abschnitt „server/share“ das Volume. Zum Beispiel entspricht der Abschnitt „server/share“ in \\?\server1\utilities\\filecomparer\ dem Teil server1\utilities. Dies ist beim Aufrufen einer Methode wie Path.GetFullPath(String, String) bei relativen Verzeichnissegmenten von Bedeutung. Es ist nie möglich, über das Volume zu navigieren.

DOS-Gerätepfade sind definitionsgemäß vollständig qualifiziert und können nicht mit einem relativen Verzeichnissegment (. oder ..) beginnen. Aktuelle Verzeichnisse haben bei Verwendung von UNC-Pfaden keine Relevanz.

Beispiel: Möglichkeiten zum Verweisen auf dieselbe Datei

Im folgenden Beispiel werden einige der Möglichkeiten veranschaulicht, wie Sie auf eine Datei verweisen können, wenn Sie die APIs im System.IO Namespace verwenden. Im Beispiel wird ein FileInfo Objekt instanziiert und seine Name Eigenschaften Length verwendet, um den Dateinamen und die Länge der Datei anzuzeigen.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        string[] filenames = {
            @"c:\temp\test-file.txt",
            @"\\127.0.0.1\c$\temp\test-file.txt",
            @"\\LOCALHOST\c$\temp\test-file.txt",
            @"\\.\c:\temp\test-file.txt",
            @"\\?\c:\temp\test-file.txt",
            @"\\.\UNC\LOCALHOST\c$\temp\test-file.txt" };

        foreach (string filename in filenames)
        {
            FileInfo fi = new(filename);
            Console.WriteLine($"file {fi.Name}: {fi.Length:N0} bytes");
        }
    }
}
// The example displays output like the following:
//      file test-file.txt: 22 bytes
//      file test-file.txt: 22 bytes
//      file test-file.txt: 22 bytes
//      file test-file.txt: 22 bytes
//      file test-file.txt: 22 bytes
//      file test-file.txt: 22 bytes
Imports System.IO

Module Program
    Sub Main()
        Dim filenames() As String = {
                "c:\temp\test-file.txt",
                "\\127.0.0.1\c$\temp\test-file.txt",
                "\\LOCALHOST\c$\temp\test-file.txt",
                "\\.\c:\temp\test-file.txt",
                "\\?\c:\temp\test-file.txt",
                "\\.\UNC\LOCALHOST\c$\temp\test-file.txt"}

        For Each filename In filenames
            Dim fi As New FileInfo(filename)
            Console.WriteLine($"file {fi.Name}: {fi.Length:N0} bytes")
        Next
    End Sub
End Module

Pfadnormalisierung

Fast alle Pfade, die an Windows-APIs übergeben werden, werden normalisiert. Während der Normalisierung führt Windows die folgenden Schritte aus:

  • Identifiziert den Pfad.
  • Das aktuelle Verzeichnis wird auf relative Pfade angewandt.
  • Komponenten und Verzeichnistrennzeichen werden kanonisiert.
  • Wertet relative Verzeichniskomponenten aus (. für das aktuelle Verzeichnis und .. für das übergeordnete Verzeichnis).
  • Bestimmte Zeichen werden gekürzt.

Diese Normalisierung erfolgt implizit, aber Sie können dies explizit tun, indem Sie die Path.GetFullPath Methode aufrufen, die einen Aufruf der GetFullPathName()-Funktion umschließt. Sie können die Windows GetFullPathName()-Funktion auch direkt mit P/Invoke aufrufen.

Identifizieren des Pfads

Der erste Schritt bei der Pfadnormalisierung ist die Identifizierung des Pfadtyps. Pfade werden in eine der folgenden Kategorien unterteilt:

  • Sie sind Gerätepfade; das heißt, sie beginnen mit zwei Trennzeichen und einem Fragezeichen oder Punkt (\\? oder \\.).
  • UNC-Pfade, d.h. sie beginnen mit zwei Trennzeichen ohne einem Fragezeichen oder Punkt.
  • Absolute DOS-Pfade, d.h. sie beginnen mit einem Laufwerkbuchstaben, einem Volumetrennzeichen und einem Komponententrennzeichen (C:\).
  • Sie legen ein Legacygerät fest (CON, LPT1).
  • Sie sind relativ zum Stamm des aktuellen Laufwerks, d.h. sie beginnen mit einem einzelnen Komponententrennzeichen (\).
  • Sie sind relativ zum aktuellen Verzeichnis eines angegebenen Laufwerks, d.h. sie beginnen mit einem Laufwerkbuchstaben, einem Volumetrennzeichen und keinem Komponententrennzeichen (C:).
  • Sie sind relativ zum aktuellen Verzeichnis; das heißt, sie beginnen mit allem anderen (temp\testfile.txt).

Der Pfadtyp bestimmt, ob ein aktuelles Verzeichnis auf irgendeine Weise angewendet wird. Außerdem wird bestimmt, was der "Stamm" des Pfads ist.

Verarbeiten von Legacygeräten

Wenn der Pfad ein älteres DOS-Gerät wie CON, COM1 oder LPT1 ist, wird er durch das Voranstellen von \\.\ in einen Gerätepfad konvertiert und zurückgegeben.

Vor Windows 11 wird ein Pfad, der mit einem älteren Gerätenamen beginnt, von der Path.GetFullPath(String) Methode immer als ein älteres Gerät interpretiert. Zum Beispiel lautet der DOS-Gerätepfad für CON.TXT\\.\CON, und der DOS-Gerätepfad für COM1.TXT\file1.txt lautet \\.\COM1. Da dies nicht mehr für Windows 11 gilt, geben Sie den vollständigen Pfad zum älteren DOS-Gerät an, zum Beispiel \\.\CON.

Anwenden des aktuellen Verzeichnisses

Wenn ein Pfad nicht vollständig qualifiziert ist, wendet Windows das aktuelle Verzeichnis darauf an. Das aktuelle Verzeichnis wird nicht auf UNC- und Gerätepfade angewendet. Es wird auch nicht auf ein volles Laufwerk mit dem Trennzeichen C:\ angewendet.

Wenn der Pfad mit einem einzelnen Komponententrennzeichen beginnt, wird das Laufwerk des aktuellen Verzeichnisses angewendet. Wenn der Dateipfad \utilities und das aktuelle Verzeichnis C:\temp\ ist, ergibt die Normalisierung C:\utilities.

Wenn der Pfad mit einem Laufwerkbuchstaben, einem Volumetrennzeichen und keinem Komponententrennzeichen beginnt, wird das letzte über die Befehlsshell festgelegte aktuelle Verzeichnis für das angegebene Laufwerk angewendet. Wenn das letzte aktuelle Verzeichnis nicht festgelegt wurde, wird nur das Laufwerk angewendet. Wenn der Dateipfad z. B D:sources. lautet, lautet C:\Documents\das aktuelle Verzeichnis , und das letzte aktuelle Verzeichnis auf Laufwerk D: lautet D:\sources\, lautet das Ergebnis D:\sources\sources. Diese "laufwerkrelativen" Pfade sind eine häufige Quelle von Programm- und Skriptlogikfehlern. Die Annahme, dass ein Pfad, der mit einem Buchstaben und einem Doppelpunkt beginnt, nicht relativ ist, ist offensichtlich nicht korrekt.

Wenn der Pfad mit etwas anderem als einem Trennzeichen beginnt, werden das aktuelle Laufwerk und das aktuelle Verzeichnis angewendet. Wenn der Pfad filecompare ist und das aktuelle Verzeichnis C:\utilities\ ist, ist das Ergebnis C:\utilities\filecompare\.

Von Bedeutung

Relative Pfade sind in Multithreadanwendungen gefährlich (d. h. die meisten Anwendungen), da das aktuelle Verzeichnis eine Prozesseinstellung ist. Jeder Thread kann das aktuelle Verzeichnis jederzeit ändern. Ab .NET Core 2.1 können Sie die Path.GetFullPath(String, String) Methode aufrufen, um einen absoluten Pfad aus einem relativen Pfad und dem Basispfad (dem aktuellen Verzeichnis), mit dem Sie ihn auflösen möchten, abzurufen.

Umwandeln von Trennzeichen in eine kanonische Form

Alle Schrägstriche (/) werden in das standardmäßige Windows-Trennzeichen, den Backslash (\), konvertiert. Wenn sie vorhanden sind, wird eine Reihe von Schrägstrichen, die auf die ersten zwei Schrägstriche folgt, auf einen einzelnen Schrägstrich reduziert.

Hinweis

Ab .NET 8 auf Unix-basierten Betriebssystemen konvertiert die Laufzeit nicht mehr umgekehrte Schrägstriche (\) in Verzeichnistrennzeichen (Schrägstriche /). Weitere Informationen finden Sie unter Backslash-Zuordnung in Unix-Dateipfaden.

Auswerten relativer Komponenten

Während der Pfad verarbeitet wird, werden alle Komponenten oder Segmente ausgewertet, die aus einem oder zwei Punkten (. oder ..) bestehen:

  • Für einen einzelnen Zeitraum wird das aktuelle Segment entfernt, da es sich auf das aktuelle Verzeichnis bezieht.

  • Bei zwei Punkten werden das aktuelle Segment und das übergeordnete Segment entfernt, da die zwei Punkte auf das übergeordnetes Verzeichnis verweisen.

    Übergeordnete Verzeichnisse werden nur entfernt, wenn sie sich nicht nach dem Stamm des Pfads befinden. Die Wurzel des Pfads hängt vom Pfadtyp ab. Für DOS-Pfade ist es das Laufwerk (C:\), für UNC-Pfade ist es „server/share“ (\\Server\Share) und für Gerätepfade ist es das Gerätepfadpräfix (\\?\ oder \\.\).

Kürzen von Zeichen

Zusätzlich zu den Ausführungen von Trennzeichen und Segmenten, die weiter oben entfernt wurden, werden einige zusätzliche Zeichen während der Normalisierung entfernt:

  • Wenn ein Segment mit einem einzelnen Punkt endet, wird der Punkt entfernt. (Ein Segment einer einzelnen oder doppelten Periode wird im vorherigen Schritt normalisiert. Ein Segment von drei oder mehr Zeiträumen wird nicht normalisiert und ist tatsächlich ein gültiger Datei-/Verzeichnisname.)

  • Wenn der Pfad nicht mit einem Trennzeichen endet, werden alle nachfolgenden Punkte und Leerzeichen (U+0020) entfernt. Wenn das letzte Segment einfach eine einzelne oder doppelte Periode ist, fällt es unter die oben genannte Regel für relative Komponenten.

    Diese Regel bedeutet, dass Sie einen Verzeichnisnamen mit einem nachfolgendem Leerzeichen erstellen können, indem Sie nach dem Leerzeichen ein Trennzeichen hinzufügen.

    Von Bedeutung

    Sie sollten nie Verzeichnisse oder Dateinamen mit nachstehenden Leerzeichen erstellen. Nachfolgende Leerzeichen können den Zugriff auf ein Verzeichnis erschweren oder unmöglich machen, und Anwendungen schlagen häufig fehl, wenn sie versuchen, Verzeichnisse oder Dateien zu behandeln, deren Namen nachfolgende Leerzeichen enthalten.

Normalisierung überspringen

Normalerweise wird jeder an eine Windows-API übergebene Pfad (effektiv) an die GetFullPathName-Funktion übergeben und normalisiert. Es gibt eine wichtige Ausnahme: ein Gerätepfad, der mit einem Fragezeichen statt einem Punkt beginnt. Sofern der Pfad nicht mit \\?\ beginnt (beachten Sie die Verwendung des kanonischen umgekehrten Schrägstrichs), ist er normalisiert.

Warum möchten Sie die Normalisierung überspringen? Es gibt drei Hauptgründe:

  1. Um Zugriff auf Pfade zu erhalten, die normalerweise nicht verfügbar sind, aber legal sind. Eine Datei oder ein Verzeichnis, das beispielsweise hidden. genannt wird, ist auf keine andere Weise zugänglich.

  2. Um die Leistung zu verbessern, indem Sie die Normalisierung überspringen, wenn Sie bereits normalisiert sind.

  3. Nur im .NET Framework kann man die MAX_PATH Überprüfung der Pfadlänge überspringen, um Pfade mit mehr als 259 Zeichen zuzulassen. Die meisten APIs ermöglichen dies mit einigen Ausnahmen.

Hinweis

.NET Core und .NET 5+ behandeln lange Pfade implizit und führen keine MAX_PATH-Prüfung durch. Die MAX_PATH Prüfung gilt nur für .NET Framework.

Das Überspringen der Normalisierung und der maximalen Pfadüberprüfungen ist der einzige Unterschied zwischen den beiden Gerätepfadsyntaxen; sie sind ansonsten identisch. Seien Sie vorsichtig beim Überspringen der Normalisierung, da Sie leicht Pfade erstellen können, die für "normale" Anwendungen schwierig sind.

Pfade, die beginnen \\?\ , werden weiterhin normalisiert, wenn Sie sie explizit an die GetFullPathName-Funktion übergeben.

Sie können Pfade mit mehr als MAX_PATH Zeichen an GetFullPathName ohne \\?\ übergeben. Sie unterstützt beliebige Längenpfade bis zur maximalen Zeichenfolgengröße, die Windows verarbeiten kann.

Fall und Windows-Dateisystem

Eine Besonderheit des Windows-Dateisystems, das Nicht-Windows-Benutzer und Entwickler verwirrend finden, ist, dass Pfad- und Verzeichnisnamen die Groß-/Kleinschreibung nicht beachten. Das bedeutet, dass Verzeichnis- und Dateinamen die Schreibweise der Zeichenfolgen darstellen, mit der sie erstellt wurden. Beispiel: Der Methodenaufruf

Directory.Create("TeStDiReCtOrY");
Directory.Create("TeStDiReCtOrY")

erstellt ein Verzeichnis mit dem Namen "TeStDiReCtOrY". Wenn Sie ein Verzeichnis oder eine Datei umbenennen, um die Groß-/Kleinschreibung zu ändern, wird die entsprechende Zeichenfolge angezeigt, die Sie beim Umbenennen eingegeben haben. Der folgende Code benennt beispielsweise eine Datei namens test.txt in Test.txtum:

using System.IO;

class Example3
{
    static void Main()
    {
        var fi = new FileInfo(@".\test.txt");
        fi.MoveTo(@".\Test.txt");
    }
}
Imports System.IO

Module Example3
    Public Sub Main()
        Dim fi As New FileInfo(".\test.txt")
        fi.MoveTo(".\Test.txt")
    End Sub
End Module

Allerdings berücksichtigen Vergleiche von Verzeichnis- und Dateinamen die Groß-/Kleinschreibung nicht. Wenn Sie nach einer Datei namens "test.txt" suchen, ignorieren .NET-Dateisystem-APIs den Fall im Vergleich. "Test.txt", "TEST.TXT", "test.TXT" und jede andere Kombination aus Groß- und Kleinbuchstaben entspricht "test.txt".