Formatos de caminho de arquivo em sistemas Windows
Os membros de muitos dos tipos no System.IO namespace incluem um path
parâmetro que permite especificar um caminho absoluto ou relativo para um recurso do sistema de arquivos. Esse caminho é então passado para APIs do sistema de arquivos do Windows. Este tópico discute os formatos para caminhos de arquivo que você pode usar em sistemas Windows.
Caminhos DOS tradicionais
Um caminho DOS padrão pode consistir em três componentes:
- Um volume ou letra de unidade seguida pelo separador de volume (
:
). - Um nome de diretório. O caractere separador de diretório separa subdiretórios dentro da hierarquia de diretório aninhada.
- Um nome de arquivo opcional. O caractere separador de diretório separa o caminho do arquivo e o nome do arquivo.
Se todos os três componentes estiverem presentes, o caminho será absoluto. Se nenhum volume ou letra de unidade for especificado e o nome do diretório começar com o caractere separador de diretório, o caminho será relativo a partir da raiz da unidade atual. Caso contrário, o caminho é relativo ao diretório atual. A tabela a seguir mostra alguns caminhos possíveis de diretório e arquivo.
Caminho | Description |
---|---|
C:\Documents\Newsletters\Summer2018.pdf |
Um caminho de arquivo absoluto da raiz da unidade C: . |
\Program Files\Custom Utilities\StringFinder.exe |
Um caminho relativo da raiz da unidade atual. |
2018\January.xlsx |
Um caminho relativo para um arquivo em um subdiretório do diretório atual. |
..\Publications\TravelBrochure.pdf |
Um caminho relativo para um arquivo em um diretório a partir do diretório atual. |
C:\Projects\apilibrary\apilibrary.sln |
Um caminho absoluto para um arquivo a partir da raiz da unidade C: . |
C:Projects\apilibrary\apilibrary.sln |
Um caminho relativo do diretório atual da C: unidade. |
Importante
Observe a diferença entre os dois últimos caminhos. Ambos especificam o especificador de volume opcional (C:
em ambos os casos), mas o primeiro começa com a raiz do volume especificado, enquanto o segundo não. Como resultado, o primeiro é um caminho absoluto do diretório raiz da unidade C:
, enquanto o segundo é um caminho relativo do diretório atual da unidade C:
. O uso do segundo formulário quando o primeiro é pretendido é uma fonte comum de bugs que envolvem caminhos de arquivo do Windows.
Você pode determinar se um caminho de arquivo é totalmente qualificado (ou seja, se o caminho é independente do diretório atual e não muda quando o diretório atual é alterado) chamando o Path.IsPathFullyQualified método. Observe que esse caminho pode incluir segmentos de diretório relativos (.
e ..
) e ainda ser totalmente qualificado se o caminho resolvido sempre apontar para o mesmo local.
O exemplo a seguir ilustra a diferença entre caminhos absolutos e relativos. Ele pressupõe que o diretório D:\FY2018\
existe e que você não definiu nenhum diretório atual para D:\
a partir do prompt de comando antes de executar o exemplo.
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
Caminhos UNC
Os caminhos UNC (convenção universal de nomenclatura), que são usados para acessar recursos de rede, têm o seguinte formato:
- Um nome de servidor ou host, que é precedido por
\\
. O nome do servidor pode ser um nome de máquina NetBIOS ou um endereço IP/FQDN (IPv4 e v6 são suportados). - Um nome de compartilhamento, que é separado do nome do host por
\
. Juntos, o servidor e o nome do compartilhamento compõem o volume. - Um nome de diretório. O caractere separador de diretório separa subdiretórios dentro da hierarquia de diretório aninhada.
- Um nome de arquivo opcional. O caractere separador de diretório separa o caminho do arquivo e o nome do arquivo.
Seguem-se alguns exemplos de percursos UNC:
Caminho | Description |
---|---|
\\system07\C$\ |
O diretório raiz da C: unidade em system07 . |
\\Server2\Share\Test\Foo.txt |
O Foo.txt arquivo no diretório Test do \\Server2\Share volume. |
Os caminhos UNC devem ser sempre totalmente qualificados. Eles podem incluir segmentos de diretório relativos (.
e ..
), mas eles devem fazer parte de um caminho totalmente qualificado. Você pode usar caminhos relativos somente mapeando um caminho UNC para uma letra de unidade.
Caminhos de dispositivo DOS
O sistema operacional Windows tem um modelo de objeto unificado que aponta para todos os recursos, incluindo arquivos. Esses caminhos de objeto são acessíveis a partir da janela do console e são expostos à camada Win32 por meio de uma pasta especial de links simbólicos para os quais os caminhos DOS e UNC herdados são mapeados. Esta pasta especial é acessada através da sintaxe do caminho do dispositivo DOS, que é uma das:
\\.\C:\Test\Foo.txt
\\?\C:\Test\Foo.txt
Além de identificar uma unidade por sua letra de unidade, você pode identificar um volume usando seu GUID de volume. Isto assume a forma:
\\.\Volume{b75e2c83-0000-0000-0000-602f00000000}\Test\Foo.txt
\\?\Volume{b75e2c83-0000-0000-0000-602f00000000}\Test\Foo.txt
Nota
A sintaxe do caminho do dispositivo DOS é suportada em implementações .NET executadas no Windows a partir do .NET Core 1.1 e do .NET Framework 4.6.2.
O caminho do dispositivo DOS consiste nos seguintes componentes:
O especificador de caminho de dispositivo (
\\.\
ou\\?\
), que identifica o caminho como um caminho de dispositivo DOS.Nota
O
\\?\
é suportado em todas as versões do .NET Core e .NET 5+ e no .NET Framework a partir da versão 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).
O primeiro segmento do caminho do dispositivo DOS após o especificador de caminho do dispositivo identifica o volume ou a unidade. (Por exemplo,
\\?\C:\
e\\.\BootPartition\
.)Existe uma ligação específica para as UNC que se chama, não surpreendentemente,
UNC
. Por exemplo:\\.\UNC\Server\Share\Test\Foo.txt
\\?\UNC\Server\Share\Test\Foo.txt
Para UNCs de dispositivo, a parte servidor/compartilhamento forma o volume. Por exemplo, no
\\?\server1\utilities\\filecomparer\
, a parte servidor/compartilhamento éserver1\utilities
. Isso é significativo ao chamar um método, como Path.GetFullPath(String, String) com segmentos de diretório relativos, nunca é possível navegar além do volume.
Os caminhos de dispositivo DOS são totalmente qualificados por definição e não podem começar com um segmento de diretório relativo (.
ou ..
). Os diretórios atuais nunca entram em seu uso.
Exemplo: Formas de fazer referência ao mesmo ficheiro
O exemplo a seguir ilustra algumas das maneiras pelas quais você pode fazer referência a um arquivo ao usar as APIs no System.IO namespace. O exemplo instancia um FileInfo objeto e usa suas Name propriedades e Length para exibir o nome do arquivo e o comprimento do arquivo.
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
Normalização de caminho
Quase todos os caminhos passados para APIs do Windows são normalizados. Durante a normalização, o Windows executa as seguintes etapas:
- Identifica o caminho.
- Aplica o diretório atual a caminhos parcialmente qualificados (relativos).
- Canonicaliza separadores de componentes e diretórios.
- Avalia os componentes relativos do diretório (
.
para o diretório atual e..
para o diretório pai). - Corta determinados caracteres.
Essa normalização acontece implicitamente, mas você pode fazê-lo explicitamente chamando o Path.GetFullPath método, que encapsula uma chamada para a função GetFullPathName(). Você também pode chamar a função GetFullPathName() do Windows diretamente usando P/Invoke.
Identificar o caminho
O primeiro passo na normalização do caminho é identificar o tipo de caminho. Os caminhos se enquadram em uma das poucas categorias:
- São caminhos de dispositivos; ou seja, começam com dois separadores e um ponto de interrogação ou ponto (
\\?
ou\\.
). - São caminhos UNC; ou seja, começam com dois separadores sem ponto de interrogação ou ponto.
- São caminhos DOS totalmente qualificados; ou seja, eles começam com uma letra de unidade, um separador de volume e um separador de componente (
C:\
). - Eles designam um dispositivo herdado (
CON
,LPT1
). - Eles são relativos à raiz da unidade atual; ou seja, começam com um único separador de componente (
\
). - Eles são relativos ao diretório atual de uma unidade especificada; ou seja, eles começam com uma letra de unidade, um separador de volume e nenhum separador de componente (
C:
). - Eles são relativos ao diretório atual; ou seja, começam com qualquer outra coisa (
temp\testfile.txt
).
O tipo do caminho determina se um diretório atual é ou não aplicado de alguma forma. Também determina qual é a "raiz" do caminho.
Lidar com dispositivos legados
Se o caminho for um dispositivo DOS herdado, como CON
, COM1
ou LPT1
, ele será convertido em um caminho de dispositivo por pré-pendente \\.\
e retornado.
Antes do Windows 11, um caminho que começa com um nome de dispositivo herdado é sempre interpretado como um dispositivo herdado pelo Path.GetFullPath(String) método. Por exemplo, o caminho do dispositivo DOS para CON.TXT
é \\.\CON
, e o caminho do dispositivo DOS para COM1.TXT\file1.txt
é \\.\COM1
. Como isso não se aplica mais ao Windows 11, especifique o caminho completo para o dispositivo DOS herdado, como \\.\CON
.
Aplicar o diretório atual
Se um caminho não estiver totalmente qualificado, o Windows aplicará o diretório atual a ele. UNCs e caminhos de dispositivo não têm o diretório atual aplicado. Nem uma unidade completa com separador C:\
.
Se o caminho começar com um único separador de componente, a unidade do diretório atual será aplicada. Por exemplo, se o caminho do arquivo for \utilities
e o diretório atual for C:\temp\
, a normalização produzirá C:\utilities
.
Se o caminho começar com uma letra de unidade, separador de volume e nenhum separador de componente, o último diretório atual definido do shell de comando para a unidade especificada será aplicado. Se o último diretório atual não foi definido, a unidade sozinha é aplicada. Por exemplo, se o caminho do arquivo for D:sources
, o diretório atual for C:\Documents\
, e o último diretório atual na unidade D: was D:\sources\
, o resultado será D:\sources\sources
. Esses caminhos "relativos à unidade" são uma fonte comum de erros de lógica de programa e script. Supor que um caminho que começa com uma letra e dois pontos não é relativo obviamente não é correto.
Se o caminho começar com algo diferente de um separador, a unidade atual e o diretório atual serão aplicados. Por exemplo, se o caminho for filecompare
e o diretório atual for C:\utilities\
, o resultado será C:\utilities\filecompare\
.
Importante
Os caminhos relativos são perigosos em aplicativos multithreaded (ou seja, a maioria dos aplicativos) porque o diretório atual é uma configuração por processo. Qualquer thread pode alterar o diretório atual a qualquer momento. A partir do .NET Core 2.1, você pode chamar o Path.GetFullPath(String, String) método para obter um caminho absoluto de um caminho relativo e o caminho base (o diretório atual) contra o qual deseja resolvê-lo.
Separadores canonicalizados
Todas as barras (/
) são convertidas no separador padrão do Windows, a barra invertida (\
). Se estiverem presentes, uma série de barras que se seguem às duas primeiras barras são colapsadas numa única barra.
Nota
A partir do .NET 8 em sistemas operacionais baseados em Unix, o tempo de execução não converte mais caracteres de barra invertida (\
) em separadores de diretório (barras /
para frente). Para obter mais informações, consulte Mapeamento de barra invertida em caminhos de arquivo Unix.
Avaliar componentes relativos
À medida que o caminho é processado, quaisquer componentes ou segmentos que são compostos por um único ou um período duplo (.
ou ..
) são avaliados:
Por um único período, o segmento atual é removido, uma vez que se refere ao diretório atual.
Para um período duplo, o segmento atual e o segmento pai são removidos, uma vez que o período duplo refere-se ao diretório pai.
Os diretórios pai só são removidos se não passarem da raiz do caminho. A raiz do caminho depende do tipo de caminho. É a unidade (
C:\
) para caminhos DOS, o servidor/compartilhamento para UNCs (\\Server\Share
) e o prefixo de caminho de dispositivo para caminhos de dispositivo (\\?\
ou\\.\
).
Cortar caracteres
Juntamente com as execuções de separadores e segmentos relativos removidos anteriormente, alguns caracteres adicionais são removidos durante a normalização:
Se um segmento terminar em um único período, esse período será removido. (Um segmento de um período único ou duplo é normalizado na etapa anterior. Um segmento de três ou mais períodos não é normalizado e é, na verdade, um nome de arquivo/diretório válido.)
Se o caminho não terminar em um separador, todos os períodos e espaços à direita (U+0020) serão removidos. Se o último segmento for simplesmente um período único ou duplo, ele se enquadra na regra de componentes relativos acima.
Esta regra significa que você pode criar um nome de diretório com um espaço à direita adicionando um separador à direita após o espaço.
Importante
Você nunca deve criar um diretório ou nome de arquivo com um espaço à direita. Os espaços à direita podem dificultar ou impossibilitar o acesso a um diretório, e os aplicativos geralmente falham ao tentar manipular diretórios ou arquivos cujos nomes incluem espaços à direita.
Ignorar normalização
Normalmente, qualquer caminho passado para uma API do Windows é (efetivamente) passado para a função GetFullPathName e normalizado. Há uma exceção importante: um caminho de dispositivo que começa com um ponto de interrogação em vez de um ponto. A menos que o caminho comece exatamente com \\?\
(observe o uso da barra invertida canônica), ele é normalizado.
Por que você gostaria de pular a normalização? Existem três razões principais:
Para ter acesso a caminhos que normalmente não estão disponíveis, mas são legais. Um arquivo ou diretório chamado
hidden.
, por exemplo, é impossível de acessar de qualquer outra forma.Para melhorar o desempenho ignorando a normalização se você já tiver normalizado.
Somente no .NET Framework, ignore a verificação do comprimento do
MAX_PATH
caminho para permitir caminhos maiores que 259 caracteres. A maioria das APIs permite isso, com algumas exceções.
Nota
O .NET Core e o .NET 5+ lidam com caminhos longos implicitamente e não executam uma MAX_PATH
verificação. A MAX_PATH
verificação aplica-se apenas ao .NET Framework.
Ignorar a normalização e as verificações de caminho máximo é a única diferença entre as duas sintaxes de caminho do dispositivo; de outro modo, são idênticos. Tenha cuidado ao pular a normalização, pois você pode facilmente criar caminhos difíceis para aplicativos "normais" lidarem.
Os caminhos que começam com \\?\
ainda são normalizados se você passá-los explicitamente para a função GetFullPathName.
Você pode passar caminhos de mais de MAX_PATH
caracteres para GetFullPathName sem \\?\
. Ele suporta caminhos de comprimento arbitrário até o tamanho máximo de cadeia de caracteres que o Windows pode manipular.
Case e o sistema de arquivos do Windows
Uma peculiaridade do sistema de arquivos do Windows que os usuários e desenvolvedores que não são do Windows acham confuso é que os nomes de caminho e diretório não diferenciam maiúsculas de minúsculas. Ou seja, os nomes de diretório e arquivo refletem o invólucro das cadeias de caracteres usadas quando são criadas. Por exemplo, a chamada de método
Directory.Create("TeStDiReCtOrY");
Directory.Create("TeStDiReCtOrY")
cria um diretório chamado TeStDiReCtOrY. Se você renomear um diretório ou arquivo para alterar suas maiúsculas e minúsculas, o diretório ou nome do arquivo refletirá o caso da cadeia de caracteres usada quando você o renomeia. Por exemplo, o código a seguir renomeia um arquivo chamado test.txt para 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
No entanto, as comparações de diretório e nome de arquivo não diferenciam maiúsculas de minúsculas. Se você procurar um arquivo chamado "test.txt", as APIs do sistema de arquivos .NET ignoram maiúsculas e minúsculas na comparação. "Test.txt", "TEST.TXT", "test.TXT" e qualquer outra combinação de letras maiúsculas e minúsculas corresponderão a "test.txt".