Formatos de caminho de arquivo em sistemas WindowsFile path formats on Windows systems

Membros de muitos dos tipos no namespace System.IO incluem um parâmetro path que permite que você especifique um caminho absoluto ou relativo para um recurso do sistema de arquivos.Members of many of the types in the System.IO namespace include a path parameter that lets you specify an absolute or relative path to a file system resource. Em seguida, esse caminho é passado para as APIs do sistema de arquivos do Windows.This path is then passed to Windows file system APIs. Este tópico discute os formatos de caminhos de arquivo que podem ser usados em sistemas do Windows.This topic discusses the formats for file paths that you can use on Windows systems.

Caminhos DOS tradicionaisTraditional DOS paths

Um caminho DOS padrão pode consistir em três componentes:A standard DOS path can consist of three components:

Se todos os três componentes estiverem presentes, o caminho será absoluto.If all three components are present, the path is absolute. Se nenhum volume ou letra da unidade for especificado e o nome do diretório começar com o caractere separador de diretório, o caminho será relativo na raiz da unidade atual.If no volume or drive letter is specified and the directory name begins with the directory separator character, the path is relative from the root of the current drive. Caso contrário, o caminho será relativo ao diretório atual.Otherwise, the path is relative to the current directory. A tabela a seguir mostra alguns possíveis caminhos de arquivo e diretório.The following table shows some possible directory and file paths.

CaminhoPath DescriçãoDescription
C:\Documents\Newsletters\Summer2018.pdf Um caminho de arquivo absoluto da raiz da unidade C:An absolute file path from the root of drive C:
\Program Files\Custom Utilities\StringFinder.exe Um caminho absoluto da raiz da unidade atual.An absolute path from the root of the current drive.
2018\January.xlsx Um caminho relativo para um arquivo em um subdiretório do diretório atual.A relative path to a file in a subdirectory of the current directory.
..\Publications\TravelBrochure.pdf Um caminho relativo para um arquivo em um diretório par do diretório atual.A relative path to file in a directory that is a peer of the current directory.
C:\Projects\apilibrary\apilibrary.sln Um caminho absoluto para um arquivo na raiz da unidade C:An absolute path to a file from the root of drive C:
C:Projects\apilibrary\apilibrary.sln Um caminho relativo do diretório atual da unidade C:.A relative path from the current directory of the C: drive.

Importante

Observe a diferença entre os últimos dois caminhos.Note the difference between the last two paths. Ambos especificam o especificador de volume opcional (C: em ambos os casos), mas o primeiro começa com a raiz do volume especificado, e o segundo não.Both specify the optional volume specifier (C: in both cases), but the first begins with the root of the specified volume, whereas the second does not. Assim, o primeiro é um caminho absoluto do diretório raiz da unidade C:, ao passo que o segundo é um caminho relativo do diretório atual da unidade C:.As result, the first is an absolute path from the root directory of drive C:, whereas the second is a relative path from the current directory of drive C:. Uso do segundo formulário quando o primeiro é uma fonte comum de bugs que envolvem caminhos de arquivo do Windows.Use of the second form when the first is intended is a common source of bugs that involve Windows file paths.

É possível determinar se um caminho de arquivo é totalmente qualificado (ou seja, se o caminho é independente do diretório atual e não se altera quando o diretório atual é alterado) chamando o método IsPathFullyQualified.You can determine whether a file path is fully qualified (that is, it the path is independent of the current directory and does not change when the current directory changes) by calling the IsPathFullyQualified method. Esse tipo de caminho poderá incluir segmentos de diretório relativo (. e ..) e ainda ser totalmente qualificado se o caminho resolvido sempre apontar para o mesmo local.Note that such a path can include relative directory segments (. and ..) and still be fully qualified if the resolved path always points to the same location.

O exemplo a seguir ilustra a diferença entre caminhos absolutos e relativos.The following example illustrates the difference between absolute and relative paths. Ele pressupõe que o diretório D:\FY2018\ existe e que nenhum diretório atual foi definido para D:\ no prompt de comando antes da execução do exemplo.It assumes that the directory D:\FY2018\ exists, and that you haven't set any curent directory for D:\ from the command prompt before running the example.

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

public class Example
{
   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 Uri(Assembly.GetExecutingAssembly().GetName().CodeBase, UriKind.Absolute);
         string commandLine = $"/C cd D:\\FY2018 & \"{currentExe.LocalPath}\" stop";
         ProcessStartInfo psi = new ProcessStartInfo("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.Diagnostics
Imports System.IO
Imports System.Reflection

Public Module Example

   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

Caminhos UNCUNC paths

Os caminhos UNC (convenção de nomenclatura universal), usados para acessar recursos de rede, têm o seguinte formato:Universal naming convention (UNC) paths, which are used to access network resources, have the following format:

  • Um nome do host ou servidor, que é precedido por \\.A server or host name, which is prefaced by \\. O nome do servidor pode ser um nome de computador NetBIOS ou um endereço IP/FQDN (IPv4 e v6 são compatíveis).The server name can be a NetBIOS machine name or an IP/FQDN address (IPv4 as well as v6 are supported).
  • Um nome do compartilhamento, separado do nome do host por \.A share name, which is separated from the host name by \. Juntos, o servidor e o nome do compartilhamento compõem o volume.Together, the server and share name make up the volume.
  • Um nome de diretório.A directory name. O caractere separador de diretório separa subdiretórios dentro da hierarquia aninhada do diretório.The directory separator character separates subdirectories within the nested directory hierarchy.
  • Um nome de arquivo opcional.An optional filename. O caractere separador de diretório separa o caminho do arquivo e o nome do arquivo.The directory separator character separates the file path and the filename.

Veja alguns exemplos de caminhos UNC:The following are some examples of UNC paths:

CaminhoPath DescriçãoDescription
\\system07\C$\ O diretório raiz da unidade C: em system07.The root directory of the C: drive on system07.
\\Server2\Share\Test\Foo.txt O arquivo Foo.txt no diretório Teste do volume \\Server2\Share.The Foo.txt file in the Test directory of the \\Server2\Share volume.

Caminhos UNC devem sempre ser totalmente qualificados.UNC paths must always be fully qualified. Podem incluir segmentos de diretório relativo (. e ..), mas esses precisam ser parte de um caminho totalmente qualificado.They can include relative directory segments (. and ..), but these must be part of a fully qualified path. É possível usar caminhos relativos somente mapeando um caminho UNC para uma letra da unidade.You can use relative paths only by mapping a UNC path to a drive letter.

Caminhos de dispositivo DOSDOS device paths

O sistema operacional Windows tem um modelo de objeto unificado que aponta para todos os recursos, incluindo arquivos.The Windows operating system has a unified object model that points to all resources, including files. Esses caminhos de objeto podem ser acessados na janela do console e estão expostos à camada Win32 por meio de uma pasta especial de links simbólicos para as quais o DOS herdado e os caminhos UNC estão mapeados.These object paths are accessible from the console window and are exposed to the Win32 layer through a special folder of symbolic links that legacy DOS and UNC paths are mapped to. Essa pasta especial é acessada pela sintaxe do caminho de dispositivo DOS, que é uma das opções a seguir:This special folder is accessed via the DOS device path syntax, which is one of:

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

Além de identificar uma unidade pela letra, você pode identificar um volume usando a GUID do volume.In addition to identifying a drive by its drive letter, you can identify a volume by using its volume GUID. Ela assume o formato:This takes the form:

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

Observação

A sintaxe do caminho de dispositivo DOS é compatível com implementações do .NET executadas no Windows, a partir do .NET Core 1.1 e .NET Framework 4.6.2.DOS device path syntax is supported on .NET implementations running on Windows starting with .NET Core 1.1 and .NET Framework 4.6.2.

O caminho de dispositivo DOS tem os seguintes componentes:The DOS device path consists of the following components:

  • O especificador de caminho do dispositivo (\\.\ ou \\?\), que identifica o caminho como um caminho de dispositivo DOS.The device path specifier (\\.\ or \\?\), which identifies the path as a DOS device path.

    Observação

    O \\?\ é compatível com todas as versões do .NET Core e, no .NET Framework, a partir da versão 4.6.2.The \\?\ is supported in all versions of .NET Core and in the .NET Framework starting with version 4.6.2.

  • Um link simbólico para o objeto de dispositivo "real" (C: no caso de um nome de unidade ou Volume{b75e2c83-0000-0000-0000-602f00000000} no caso de um GUID de volume).A symbolic link to the "real" device object (C: in the case of a drive name, or Volume{b75e2c83-0000-0000-0000-602f00000000} in the case of a volume GUID).

    O primeiro segmento do caminho de dispositivo DOS depois do especificador de caminho do dispositivo identifica o volume ou a unidade.The first segment of the DOS device path after the device path specifier identifies the volume or drive. Por exemplo, \\?\C:\ e \\.\BootPartition\.(For example, \\?\C:\ and \\.\BootPartition\.)

    Há um link específico para UNCs que é chamado, não surpreendentemente, UNC.There is a specific link for UNCs that is called, not surprisingly, UNC. Por exemplo:For example:

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

    Para UNCs de dispositivo, a parte do servidor/compartilhamento forma o volume.For device UNCs, the server/share portion forms the volume. Por exemplo, no \\?\server1\e:\utilities\\filecomparer\, a parte do servidor/compartilhamento é server1\utilities.For example, in \\?\server1\e:\utilities\\filecomparer\, the server/share portion is server1\utilities. Isso é importante ao chamar um método como Path.GetFullPath(String, String) com segmentos de diretório relativo. Não é possível navegar além desse volume.This is significant when calling a method such as Path.GetFullPath(String, String) with relative directory segments; it is never possible to navigate past the volume.

Caminhos de dispositivo DOS são totalmente qualificados por definição.DOS device paths are fully qualified by definition. Os segmento de diretório relativo (. e ..) não são permitidos.Relative directory segments (. and ..) are not allowed. Os diretórios atuais nunca são inseridos no uso deles.Current directories never enter into their usage.

Exemplo: maneiras de se referir ao mesmo arquivoExample: Ways to refer to the same file

O exemplo a seguir mostra algumas maneiras de se referir ao arquivo ao usar as APIs do namespace System.IO.The following example illustrates some of the ways in which you can refer to a file when using the APIs in the System.IO namespace. O exemplo cria uma instância de um objeto FileInfo e usa suas propriedades Name e Length para exibir o nome do arquivo e seu tamanho.The example instantiates a FileInfo object and uses its Name and Length properties to display the filename and the length of the file.

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",
            @"\\127.0.0.1\c$\temp\test-file.txt" };

        foreach (var filename in filenames)
        {
            FileInfo fi = new FileInfo(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
//      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",
                "\\127.0.0.1\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

Normalização de caminhoPath normalization

Quase todos os caminhos passados para APIs do Windows são normalizados.Almost all paths passed to Windows APIs are normalized. Durante a normalização, o Windows executa as seguintes etapas:During normalization, Windows performs the following steps:

  • Identifica o caminho.Identifies the path.
  • Aplica o diretório atual a caminhos (relativos) parcialmente qualificados.Applies the current directory to partially qualified (relative) paths.
  • Canoniza os separadores de diretório e componente.Canonicalizes component and directory separators.
  • Avalia os componentes do diretório relativo (. para o diretório atual e .. para o diretório pai).Evaluates relative directory components (. for the current directory and .. for the parent directory).
  • Corta alguns caracteres.Trims certain characters.

Essa normalização ocorre de maneira implícita, mas é possível fazê-la explicitamente chamando o método Path.GetFullPath, que encapsula uma chamada para a função GetFullPathName().This normalization happens implicitly, but you can do it explicitly by calling the Path.GetFullPath method, which wraps a call to the GetFullPathName() function. Também é possível chamar a função GetFullPathName() do Windows diretamente usando P/Invoke.You can also call the Windows GetFullPathName() function directly using P/Invoke.

Identificar o caminhoIdentifying the path

O primeiro passo na normalização do caminho é identificar o tipo do caminho.The first step in path normalization is identifying the type of path. Os caminhos são classificados em uma dentre algumas categorias:Paths fall into one of a few categories:

  • São caminhos de dispositivo, ou seja, começam com dois separadores e um ponto de interrogação ou ponto final (\\? ou \\.).They are device paths; that is, they begin with two separators and a question mark or period (\\? or \\.).
  • São caminhos UNC, ou seja, começam com dois separadores sem um ponto de interrogação ou ponto final.They are UNC paths; that is, they begin with two separators without a question mark or period.
  • São caminhos DOS totalmente qualificados, ou seja, começam com uma letra da unidade, um separador de volume e um separador de componente (C:\).They are fully qualified DOS paths; that is, they begin with a drive letter, a volume separator, and a component separator (C:\).
  • Designam um dispositivo herdado (CON, LPT1).They designate a legacy device (CON, LPT1).
  • Estão relacionados com a raiz da unidade atual, ou seja, começam com um separador de componente único (\).They are relative to the root of the current drive; that is, they begin with a single component separator (\).
  • Estão relacionados com o diretório atual de uma unidade especificada, ou seja, começam com uma letra da unidade, um separador de volume e sem um separador de componente (C:).They are relative to the current directory of a specified drive; that is, they begin with a drive letter, a volume separator, and no component separator (C:).
  • Estão relacionados com o diretório atual, ou seja, começam com qualquer outra coisa (temp\testfile.txt).They are relative to the current directory; that is, they begin with anything else (temp\testfile.txt).

O tipo do caminho determina se o diretório atual é aplicado de alguma maneira ou não.The type of the path determines whether or not a current directory is applied in some way. Também determina qual é a "raiz" do caminho.It also determines what the "root" of the path is.

Tratamento de dispositivos herdadosHandling legacy devices

Se o caminho for um dispositivo DOS herdado como CON, COM1 ou LPT1, será convertido em um caminho de dispositivo pelo \\.\ precedente e retornado.If the path is a legacy DOS device such as CON, COM1, or LPT1, it is converted into a device path by prepending \\.\ and returned.

Um caminho que começa com um nome do dispositivo herdado sempre é interpretado como um dispositivo herdado pelo método Path.GetFullPath(String).A path that begins with a legacy device name is always interpreted as a legacy device by the Path.GetFullPath(String) method. Por exemplo, o caminho de dispositivo DOS de CON.TXT é \\.\CON, e o caminho de dispositivo DOS de COM1.TXT\file1.txt é \\.\COM1.For example, the DOS device path for CON.TXT is \\.\CON, and the DOS device path for COM1.TXT\file1.txt is \\.\COM1.

Aplicar o diretório atualApplying the current directory

Se o caminho não for totalmente qualificado, o Windows aplicará o diretório atual a ele.If a path isn't fully qualified, Windows applies the current directory to it. O diretório atual não foi aplicado a UNCs e caminhos de dispositivo.UNCs and device paths do not have the current directory applied. Nem a unidade total com o separador C:\.Neither does a full drive with separator C:\.

Se o caminho começar com um único separador de componente, a unidade do diretório atual será aplicada.If the path starts with a single component separator, the drive from the current directory is applied. Por exemplo, se o caminho do arquivo for \utilities e o diretório atual for C:\temp\, a normalização produzirá C:\utilities.For example, if the file path is \utilities and the current directory is C:\temp\, normalization produces C:\utilities.

Se o caminho começar com uma letra da unidade, um separador de volume e sem um separador de componente, o último diretório atual definido do shell de comando para a unidade especificada será aplicado.If the path starts with a drive letter, volume separator, and no component separator, the last current directory set from the command shell for the specified drive is applied. Se o último diretório atual não tiver sido definido, a unidade isolada será aplicada.If the last current directory was not set, the drive alone is applied. Por exemplo, se o caminho de arquivo for D:sources, o diretório atual for C:\Documents\ e o último diretório atual na unidade D: for D:\sources\, o resultado será D:\sources\sources.For example, if the file path is D:sources, the current directory is C:\Documents\, and the last current directory on drive D: was D:\sources\, the result is D:\sources\sources. Esses caminhos "relativos à unidade" são uma fonte comum de erros lógicos de script e programas.These "drive relative" paths are a common source of program and script logic errors. Assumir que um caminho iniciado com uma letra e dois-pontos não é relativo é claramente incorreto.Assuming that a path beginning with a letter and a colon isn't relative is obviously not correct.

Se o caminho começar com algo diferente de um separador, a unidade e o diretório atuais serão aplicados.If the path starts with something other than a separator, the current drive and current directory are applied. Por exemplo, se o caminho for filecompare e o diretório atual for C:\utilities\, o resultado será C:\utilities\filecompare\.For example, if the path is filecompare and the current directory is C:\utilities\, the result is C:\utilities\filecompare\.

Importante

Os caminhos relativos são perigosos em aplicativos multi-threaded (ou seja, a maioria), porque o diretório atual tem uma configuração por processo.Relative paths are dangerous in multithreaded applications (that is, most applications) because the current directory is a per-process setting. Qualquer thread pode alterar o diretório atual a qualquer momento.Any thread can change the current directory at any time. A partir do .NET Core 2.1, é possível chamar o método Path.GetFullPath(String, String) para obter um caminho absoluto de um caminho relativo, bem como o caminho base (o diretório atual) que você precisa para resolvê-lo.Starting with .NET Core 2.1, you can call the Path.GetFullPath(String, String) method to get an absolute path from a relative path and the base path (the current directory) that you want to resolve it against.

Canonizar separadoresCanonicalizing separators

Todas as barras (/) são convertidas no separador padrão do Windows, a barra invertida (\).All forward slashes (/) are converted into the standard Windows separator, the back slash (\). Se estiverem presentes, uma série de barras que segue as duas primeiras barras serão ocultadas e exibidas como uma barra só.If they are present, a series of slashes that follow the first two slashes are collapsed into a single slash.

Avaliar componentes relativosEvaluating relative components

Conforme o caminho é processado, quaisquer componentes ou segmentos compostos de um ponto final ou ponto duplo (. ou ..) serão avaliados:As the path is processed, any components or segments that are composed of a single or a double period (. or ..) are evaluated:

  • No caso do ponto final, o segmento atual será removido, pois se refere ao diretório atual.For a single period, the current segment is removed, since it refers to the current directory.

  • No caso do ponto duplo, o segmento atual e o segmento pai serão removidos, pois o ponto duplo se refere ao diretório pai.For a double period, the current segment and the parent segment are removed, since the double period refers to the parent directory.

    Os diretórios pais só serão removidos se não forem maiores que a raiz do caminho.Parent directories are only removed if they aren't past the root of the path. A raiz do caminho depende do tipo do caminho.The root of the path depends on the type of path. É a unidade (C:\) dos caminhos DOS, o servidor/compartilhamento de UNCs (\\Server\Share) e o prefixo do caminho de dispositivo dos caminhos de dispositivo (\\?\ ou \\.\).It is the drive (C:\) for DOS paths, the server/share for UNCs (\\Server\Share), and the device path prefix for device paths (\\?\ or \\.\).

Cortar caracteresTrimming characters

Alguns outros caracteres são removidos durante a normalização junto com os separadores e segmentos relativos removidos anteriormente:Along with the runs of separators and relative segments removed earlier, some additional characters are removed during normalization:

  • Se um segmento terminar em ponto final, esse ponto final será removido.If a segment ends in a single period, that period is removed. Um segmento com ponto final ou ponto duplo foi normalizado na etapa anterior.(A segment of a single or double period is normalized in the previous step. Um segmento com três ou mais pontos não será normalizado e, na verdade, é um nome de arquivo/diretório válido.A segment of three or more periods is not normalized and is actually a valid file/directory name.)

  • Se o caminho não terminar em um separador, todos os pontos e espaços à direita (U+0020) serão removidos.If the path doesn't end in a separator, all trailing periods and spaces (U+0020) are removed. Se o último segmento for simplesmente um ponto final ou duplo, será aplicada a regra de componentes relativos já mencionada.If the last segment is simply a single or double period, it falls under the relative components rule above.

    Essa regra significa que é possível criar um nome de diretório com um espaço à direita ao adicionar um separador à direita após o espaço.This rule means that you can create a directory name with a trailing space by adding a trailing separator after the space.

    Importante

    Nunca crie um diretório ou nome de arquivo com um espaço à direita.You should never create a directory or filename with a trailing space. Os espaços à direita podem dificultar ou impossibilitar o acesso ao diretório e, normalmente, os aplicativos apresentam falha nas tentativas de tratar diretórios ou arquivos com nomes que contêm espaços à direita.Trailing spaces can make it difficult or impossible to access a directory, and applications commonly fail when attempting to handle directories or files whose names include trailing spaces.

Ignorar a normalizaçãoSkipping normalization

Normalmente, qualquer caminho passado para uma API do Windows é (efetivamente) passado para a função GetFullPathName e normalizado.Normally, any path passed to a Windows API is (effectively) passed to the GetFullPathName function and normalized. Há uma exceção importante: um caminho de dispositivo que começa com um ponto de interrogação em vez de um ponto final.There is one important exception: a device path that begins with a question mark instead of a period. A menos que o caminho comece exatamente com \\?\ (observe o uso da barra invertida canônica), ele é normalizado.Unless the path starts exactly with \\?\ (note the use of the canonical backslash), it is normalized.

Por que ignorar a normalização?Why would you want to skip normalization? Existem três motivos principais:There are three major reasons:

  1. Para ter acesso a caminhos normalmente não disponíveis, mas legais.To get access to paths that are normally unavailable but are legal. Um arquivo ou diretório chamado hidden., por exemplo, não pode ser acessado de outra maneira.A file or directory called hidden., for example, is impossible to access in any other way.

  2. Para melhorar o desempenho ignorando a normalização, se você já tiver normalizado.To improve performance by skipping normalization if you've already normalized.

  3. Somente no .NET Framework, ignorar a verificação MAX_PATH do tamanho do caminho para permitir caminhos com mais de 259 caracteres.On the .NET Framework only, to skip the MAX_PATH check for path length to allow for paths that are greater than 259 characters. A maioria das APIs permitem isso, com algumas exceções.Most APIs allow this, with some exceptions.

Observação

O .NET Core trata caminhos longos de maneira implícita e não executa uma verificação MAX_PATH..NET Core handles long paths implicitly and does not perform a MAX_PATH check. A verificação MAX_PATH se aplica somente ao .NET Framework.The MAX_PATH check applies only to the .NET Framework.

Ignorar a normalização e as verificações de tamanho do caminho é a única diferença entre as duas sintaxes de caminho de dispositivo. Caso contrário, elas serão idênticas.Skipping normalization and max path checks is the only difference between the two device path syntaxes; they are otherwise identical. Tenha cuidado ao ignorar a normalização, pois é fácil criar caminhos de difícil tratamento para aplicativos "normais".Be careful with skipping normalization, since you can easily create paths that are difficult for "normal" applications to deal with.

Os caminhos que começam com \\?\ ainda serão normalizados se você os passar explicitamente para a função GetFullPathName.Paths that start with \\?\ are still normalized if you explicitly pass them to the GetFullPathName function.

Observe que é possível criar caminhos com mais de MAX_PATH caracteres para GetFullPathName sem \\?\.Note that you can paths of more than MAX_PATH characters to GetFullPathName without \\?\. Ele dá suporte caminhos de tamanho arbitrário, até o tamanho máximo da cadeia de caracteres que o Windows consegue tratar.It supports arbitrary length paths up to the maximum string size that Windows can handle.

Maiúsculas, minúsculas e o sistema de arquivos do WindowsCase and the Windows file system

Uma peculiaridade do sistema de arquivos do Windows que usuários e desenvolvedores que não o utilizam consideram confusa é que os nomes do caminho e do diretório não diferenciam maiúsculas de minúsculas.A peculiarity of the Windows file system that non-Windows users and developers find confusing is that path and directory names are case-insensitive. Isto é, os nomes do caminho e do diretório refletem as cadeias de caracteres utilizadas no momento da criação.That is, directory and file names reflect the casing of the strings used when they are created. Por exemplo, a chamada de métodoFor example, the method call

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

cria um diretório chamado TeStDiReCtOrY.creates a directory named TeStDiReCtOrY. Se você renomear um diretório ou arquivo para alterar as maiúsculas e minúsculas, o nome do diretório ou do arquivo refletirá a cadeia de caracteres usadas ao renomeá-los.If you rename a directory or file to change its case, the directory or file name reflects the case of the string used when you rename it. Por exemplo, o código a seguir renomeia o arquivo test.txt como Test.txt:For example, the following code renames a file named test.txt to Test.txt:

using System.IO;

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

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

No entanto, as comparações entre o nome do diretório e do arquivo não diferenciam maiúsculas e minúsculas.However, directory and file name comparisons are case-insensitive. Se você pesquisar por um arquivo com o nome "test.txt", as APIs do sistema de arquivos do .NET ignorarão a comparação entre maiúsculas e minúsculas.If you search for a file named "test.txt", .NET file system APIs ignore case in the comparison. Test.txt, TEST.TXT, test.TXT e qualquer outra combinação de maiúsculas e minúsculas corresponderão a "test.txt".Test.txt, TEST.TXT, test.TXT, and any other combination of upper- and lowercase letters will match "test.txt".