Udostępnij za pośrednictwem


Formaty ścieżek plików w systemie Windows

Elementy członkowskie wielu typów w System.IO przestrzeni nazw zawierają path parametr, który umożliwia określenie ścieżki bezwzględnej lub względnej do zasobu systemu plików. Ta ścieżka jest następnie przekazywana do interfejsów API systemu plików systemu Windows. W tym temacie omówiono formaty ścieżek plików, których można używać w systemach Windows.

Tradycyjne ścieżki DOS

Standardowa ścieżka systemu DOS może składać się z trzech składników:

  • Litera woluminu lub dysku, po którym następuje separator woluminu (:).
  • Nazwa katalogu. Znak separatora katalogu oddziela podkatalogi w hierarchii zagnieżdżonych katalogów.
  • Opcjonalna nazwa pliku. Znak separatora katalogu oddziela ścieżkę pliku i nazwę pliku.

Jeśli wszystkie trzy składniki są obecne, ścieżka jest bezwzględna. Jeśli nie określono litery woluminu lub dysku, a nazwa katalogu zaczyna się od znaku separatora katalogu, ścieżka jest względna z katalogu głównego bieżącego dysku. W przeciwnym razie ścieżka jest względna do bieżącego katalogu. W poniższej tabeli przedstawiono niektóre możliwe ścieżki katalogów i plików.

Ścieżka opis
C:\Documents\Newsletters\Summer2018.pdf Bezwzględna ścieżka pliku z katalogu głównego dysku C:.
\Program Files\Custom Utilities\StringFinder.exe Ścieżka względna z katalogu głównego bieżącego dysku.
2018\January.xlsx Ścieżka względna do pliku w podkatalogu bieżącego katalogu.
..\Publications\TravelBrochure.pdf Ścieżka względna do pliku w katalogu rozpoczynającym się od bieżącego katalogu.
C:\Projects\apilibrary\apilibrary.sln Ścieżka bezwzględna do pliku z katalogu głównego dysku C:.
C:Projects\apilibrary\apilibrary.sln Ścieżka względna z bieżącego C: katalogu dysku.

Ważne

Zwróć uwagę na różnicę między dwiema ostatnimi ścieżkami. Oba określają opcjonalny specyfikator woluminu (C: w obu przypadkach), ale pierwszy zaczyna się od katalogu głównego określonego woluminu, natomiast drugi nie. W rezultacie pierwszy jest ścieżką bezwzględną z katalogu głównego dysku C:, natomiast drugi jest ścieżką względną z bieżącego katalogu dysku C:. Użycie drugiego formularza, gdy pierwszy jest przeznaczony, jest typowym źródłem usterek obejmujących ścieżki plików systemu Windows.

Można określić, czy ścieżka pliku jest w pełni kwalifikowana (czyli jeśli ścieżka jest niezależna od bieżącego katalogu i nie zmienia się, gdy bieżący katalog ulegnie zmianie) przez wywołanie Path.IsPathFullyQualified metody . Należy pamiętać, że taka ścieżka może zawierać względne segmenty katalogów (. i ..) i nadal być w pełni kwalifikowane, jeśli rozpoznana ścieżka zawsze wskazuje tę samą lokalizację.

Poniższy przykład ilustruje różnicę między ścieżkami bezwzględnymi i względnymi. Przyjęto założenie, że katalog D:\FY2018\ istnieje i że nie ustawiono żadnego bieżącego katalogu D:\ z wiersza polecenia przed uruchomieniem przykładu.

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

Ścieżki UNC

Ścieżki uniwersalnej konwencji nazewnictwa (UNC), które są używane do uzyskiwania dostępu do zasobów sieciowych, mają następujący format:

  • Nazwa serwera lub hosta poprzedzona ciągiem \\. Nazwa serwera może być nazwą maszyny NetBIOS lub adresem IP/FQDN (obsługiwane są protokoły IPv4 i v6).
  • Nazwa udziału, która jest oddzielona od nazwy hosta przez \. Razem serwer i nazwa udziału składają się na wolumin.
  • Nazwa katalogu. Znak separatora katalogu oddziela podkatalogi w hierarchii zagnieżdżonych katalogów.
  • Opcjonalna nazwa pliku. Znak separatora katalogu oddziela ścieżkę pliku i nazwę pliku.

Poniżej przedstawiono kilka przykładów ścieżek UNC:

Ścieżka opis
\\system07\C$\ Katalog C: główny dysku na .system07
\\Server2\Share\Test\Foo.txt Foo.txt Plik w katalogu Test woluminu\\Server2\Share.

Ścieżki UNC muszą być zawsze w pełni kwalifikowane. Mogą zawierać względne segmenty katalogów (. i ..), ale muszą one być częścią w pełni kwalifikowanej ścieżki. Ścieżki względne można używać tylko przez mapowanie ścieżki UNC na literę dysku.

Ścieżki urządzeń do usługi DOS

System operacyjny Windows ma ujednolicony model obiektów, który wskazuje wszystkie zasoby, w tym pliki. Te ścieżki obiektów są dostępne w oknie konsoli i są widoczne w warstwie Win32 za pośrednictwem specjalnego folderu linków symbolicznych, do których są mapowane starsze ścieżki DOS i UNC. Ten specjalny folder jest dostępny za pośrednictwem składni ścieżki urządzenia DOS, która jest jedną z następujących funkcji:

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

Oprócz identyfikacji dysku na podstawie litery dysku można zidentyfikować wolumin przy użyciu jego identyfikatora GUID woluminu. Ma to postać:

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

Uwaga

Składnia ścieżki urządzenia DOS jest obsługiwana w implementacjach platformy .NET działających w systemie Windows, począwszy od platformy .NET Core 1.1 i .NET Framework 4.6.2.

Ścieżka urządzenia DOS składa się z następujących składników:

  • Specyfikator ścieżki urządzenia (\\.\ lub \\?\), który identyfikuje ścieżkę jako ścieżkę urządzenia DOS.

    Uwaga

    Element \\?\ jest obsługiwany we wszystkich wersjach platform .NET Core i .NET 5 lub nowszych oraz w programie .NET Framework, począwszy od wersji 4.6.2.

  • Link symboliczny do obiektu urządzenia "rzeczywistego" (C: w przypadku nazwy dysku lub Volume{b75e2c83-0000-0000-0000-602f00000000} w przypadku identyfikatora GUID woluminu).

    Pierwszy segment ścieżki urządzenia DOS po specyfikatorze ścieżki urządzenia identyfikuje wolumin lub dysk. (Na przykład \\?\C:\ i \\.\BootPartition\.)

    Istnieje konkretny link dla ONZ, który jest nazywany, nic dziwnego, UNC. Na przykład:

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

    W przypadku kontrolerów UNC urządzenia część serwera/udziału tworzy wolumin. Na przykład w \\?\server1\utilities\\filecomparer\pliku część serwera/udziału to server1\utilities. Jest to istotne w przypadku wywoływania metody, takiej jak Path.GetFullPath(String, String) w przypadku względnych segmentów katalogu; nigdy nie można nawigować po woluminie.

Ścieżki urządzeń DOS są w pełni kwalifikowane według definicji i nie mogą zaczynać się od względnego segmentu katalogu (. lub ..). Bieżące katalogi nigdy nie wchodzą w ich użycie.

Przykład: sposoby odwoływania się do tego samego pliku

Poniższy przykład ilustruje niektóre sposoby odwoływania się do pliku podczas korzystania z interfejsów API w System.IO przestrzeni nazw. Przykład tworzy wystąpienie FileInfo obiektu i używa jego Name właściwości i Length do wyświetlania nazwy pliku oraz długości pliku.

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

Normalizacja ścieżki

Prawie wszystkie ścieżki przekazywane do interfejsów API systemu Windows są znormalizowane. Podczas normalizacji system Windows wykonuje następujące kroki:

  • Identyfikuje ścieżkę.
  • Stosuje bieżący katalog do częściowo kwalifikowanych (względnych) ścieżek.
  • Canonicalizuje separatory składników i katalogów.
  • Ocenia względne składniki katalogu (. dla bieżącego katalogu i .. dla katalogu nadrzędnego).
  • Przycina niektóre znaki.

Ta normalizacja odbywa się niejawnie, ale można to zrobić jawnie, wywołując Path.GetFullPath metodę , która opakowuje wywołanie funkcji GetFullPathName(). Funkcję GetFullPathName() systemu Windows można również wywołać bezpośrednio przy użyciu funkcji P/Invoke.

Identyfikowanie ścieżki

Pierwszym krokiem normalizacji ścieżki jest zidentyfikowanie typu ścieżki. Ścieżki należą do jednej z kilku kategorii:

  • Są to ścieżki urządzeń; oznacza to, że zaczynają się od dwóch separatorów i znaku zapytania lub kropki (\\? lub \\.).
  • Są to ścieżki UNC; oznacza to, że zaczynają się od dwóch separatorów bez znaku zapytania lub kropki.
  • Są to w pełni kwalifikowane ścieżki DOS; oznacza to, że zaczynają się literą dysku, separatorem woluminu i separatorem składnika (C:\).
  • Wyznaczają starsze urządzenie (CON, LPT1).
  • Są one względne względem katalogu głównego bieżącego dysku; oznacza to, że zaczynają się od jednego separatora składników (\).
  • Są one względne względem bieżącego katalogu określonego dysku; oznacza to, że zaczynają się literą dysku, separatorem woluminu i bez separatora składników (C:).
  • Są one względem bieżącego katalogu; oznacza to, że zaczynają się od niczego innego (temp\testfile.txt).

Typ ścieżki określa, czy bieżący katalog jest stosowany w jakiś sposób. Określa również, jaki jest "katalog główny" ścieżki.

Obsługa starszych urządzeń

Jeśli ścieżka jest starszym urządzeniem DOS, takim jak CON, COM1lub LPT1, jest konwertowana na ścieżkę urządzenia przez wstępne i \\.\ zwrócone.

Przed systemem Windows 11 ścieżka rozpoczynająca się od starszej nazwy urządzenia jest zawsze interpretowana jako starsze urządzenie według Path.GetFullPath(String) metody . Na przykład ścieżka urządzenia DOS dla CON.TXT parametru to \\.\CON, a ścieżka urządzenia DOS dla COM1.TXT\file1.txt parametru to \\.\COM1. Ponieważ nie dotyczy to już systemu Windows 11, określ pełną ścieżkę do starszego urządzenia DOS, na przykład \\.\CON.

Stosowanie bieżącego katalogu

Jeśli ścieżka nie jest w pełni kwalifikowana, system Windows stosuje do niego bieżący katalog. UnCs i ścieżki urządzeń nie mają zastosowanego bieżącego katalogu. Żaden z nich nie wykonuje pełnego dysku z separatorem C:\.

Jeśli ścieżka zaczyna się od jednego separatora składników, dysk z bieżącego katalogu jest stosowany. Jeśli na przykład ścieżka pliku to \utilities , a bieżący katalog to C:\temp\, normalizacja generuje wartość C:\utilities.

Jeśli ścieżka zaczyna się literą dysku, separatorem woluminu i bez separatora składników, zostanie zastosowany ostatni bieżący katalog ustawiony w powłoce poleceń dla określonego dysku. Jeśli ostatni bieżący katalog nie został ustawiony, dysk jest stosowany sam. Jeśli na przykład ścieżka pliku to , bieżący katalog to D:sourcesC:\Documents\, a ostatni bieżący katalog na dysku D: to D:\sources\, wynikiem jest D:\sources\sources. Te ścieżki "względne dysku" są typowym źródłem błędów logiki programu i skryptu. Zakładając, że ścieżka rozpoczynająca się od litery i dwukropka nie jest względna, oczywiście nie jest poprawna.

Jeśli ścieżka zaczyna się od czegoś innego niż separator, zastosowano bieżący dysk i bieżący katalog. Jeśli na przykład ścieżka to filecompare , a bieżący katalog to C:\utilities\, wynikiem jest C:\utilities\filecompare\.

Ważne

Ścieżki względne są niebezpieczne w aplikacjach wielowątkowych (czyli większości aplikacji), ponieważ bieżący katalog jest ustawieniem dla poszczególnych procesów. Każdy wątek może w dowolnym momencie zmienić bieżący katalog. Począwszy od platformy .NET Core 2.1, możesz wywołać Path.GetFullPath(String, String) metodę , aby uzyskać ścieżkę bezwzględną ze ścieżki względnej i ścieżkę podstawową (bieżący katalog), względem którego chcesz go rozpoznać.

Canonicalize separatorów

Wszystkie ukośniki (/) są konwertowane na standardowy separator systemu Windows, ukośnik odwrotny (\). Jeśli są obecne, seria ukośników, które następują po dwóch pierwszych ukośnikach, są zwinięte w jeden ukośnik.

Uwaga

Począwszy od platformy .NET 8 w systemach operacyjnych opartych na systemie Unix, środowisko uruchomieniowe nie konwertuje już znaków ukośnika odwrotnego () na separatory katalogów (\ukośniki /do przodu). Aby uzyskać więcej informacji, zobacz Mapowanie ukośników odwrotnych w ścieżkach plików systemu Unix.

Ocena składników względnych

Podczas przetwarzania ścieżki są oceniane wszystkie składniki lub segmenty składające się z jednego lub podwójnego okresu (. lub ..):

  • W przypadku pojedynczego okresu bieżący segment jest usuwany, ponieważ odwołuje się do bieżącego katalogu.

  • W przypadku podwójnego okresu bieżący segment i segment nadrzędny są usuwane, ponieważ podwójny okres odnosi się do katalogu nadrzędnego.

    Katalogi nadrzędne są usuwane tylko wtedy, gdy nie znajdują się poza katalogiem głównym ścieżki. Katalog główny ścieżki zależy od typu ścieżki. Jest to dysk (C:\) dla ścieżek DOS, serwera/udziału dla UNC (\\Server\Share) i prefiks ścieżki urządzenia dla ścieżek urządzeń (\\?\ lub \\.\).

Przycinanie znaków

Wraz z przebiegami separatorów i segmentów względnych usuniętych wcześniej niektóre dodatkowe znaki są usuwane podczas normalizacji:

  • Jeśli segment kończy się jednym okresem, ten okres zostanie usunięty. (Segment pojedynczego lub podwójnego okresu jest znormalizowany w poprzednim kroku. Segment z co najmniej trzema kropkami nie jest znormalizowany i jest w rzeczywistości prawidłową nazwą pliku/katalogu).

  • Jeśli ścieżka nie zostanie zakończona separatorem, wszystkie kropki końcowe i spacje (U+0020) zostaną usunięte. Jeśli ostatni segment jest po prostu pojedynczym lub podwójnym okresem, znajduje się on w powyższej regule względnych składników.

    Ta reguła oznacza, że można utworzyć nazwę katalogu z spacją końcową, dodając separator końcowy po spacji.

    Ważne

    Nigdy nie należy tworzyć katalogu lub nazwy pliku z spacją końcową. Spacje końcowe mogą utrudnić lub uniemożliwić dostęp do katalogu, a aplikacje często kończą się niepowodzeniem podczas próby obsługi katalogów lub plików, których nazwy obejmują spacje końcowe.

Pomiń normalizację

Zwykle każda ścieżka przekazywana do interfejsu API systemu Windows jest (skutecznie) przekazywana do funkcji GetFullPathName i znormalizowana. Istnieje jeden ważny wyjątek: ścieżka urządzenia rozpoczynająca się od znaku zapytania zamiast kropki. Chyba że ścieżka zaczyna się dokładnie \\?\ od (zwróć uwagę na użycie ukośnika kanonicznego), jest znormalizowana.

Dlaczego chcesz pominąć normalizację? Istnieją trzy główne przyczyny:

  1. Aby uzyskać dostęp do ścieżek, które są zwykle niedostępne, ale są legalne. Plik lub katalog o nazwie hidden., na przykład, jest niemożliwe do uzyskania dostępu w jakikolwiek inny sposób.

  2. Aby zwiększyć wydajność, pomijając normalizację, jeśli już znormalizowano.

  3. Tylko na platformie .NET Framework, aby pominąć MAX_PATH sprawdzanie długości ścieżki, aby zezwolić na ścieżki, które są większe niż 259 znaków. Większość interfejsów API zezwala na to, z pewnymi wyjątkami.

Uwaga

Platformy .NET Core i .NET 5+ obsługują długie ścieżki niejawnie i nie wykonują sprawdzania MAX_PATH . Sprawdzanie MAX_PATH dotyczy tylko programu .NET Framework.

Pomijanie normalizacji i maksymalnych testów ścieżek jest jedyną różnicą między dwiema składniami ścieżek urządzenia; są identyczne. Należy zachować ostrożność podczas pomijania normalizacji, ponieważ można łatwo tworzyć ścieżki, które są trudne dla "normalnych" aplikacji do obsługi.

Ścieżki rozpoczynające się od \\?\ są nadal znormalizowane, jeśli jawnie przekażesz je do funkcji GetFullPathName.

Ścieżki więcej niż MAX_PATH znaków można przekazać do metody GetFullPathName bez \\?\parametru . Obsługuje dowolne ścieżki długości do maksymalnego rozmiaru ciągu, który może obsłużyć system Windows.

Przypadek i system plików systemu Windows

Osobliwością systemu plików systemu Windows, który użytkownicy systemu windows i deweloperzy uważają za mylące, jest to, że nazwy ścieżek i katalogów są niewrażliwe na wielkość liter. Oznacza to, że nazwy katalogów i plików odzwierciedlają wielkość liter ciągów używanych podczas ich tworzenia. Na przykład wywołanie metody

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

Tworzy katalog o nazwie TeStDiReCtOrY. Jeśli zmienisz nazwę katalogu lub pliku, aby zmienić jego wielkość, nazwa katalogu lub pliku odzwierciedla przypadek ciągu użytego podczas zmieniania jego nazwy. Na przykład następujący kod zmienia nazwę pliku o nazwie test.txt na Test.txt:

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

Jednak porównania nazw katalogów i plików są bez uwzględniania wielkości liter. Jeśli wyszukasz plik o nazwie "test.txt", interfejsy API systemu plików platformy .NET ignorują przypadek w porównaniu. "Test.txt", "TEST.TXT", "test.TXT", a każda inna kombinacja wielkich i małych liter będzie pasować do "test.txt".