Formatos de ruta de acceso de archivo en los sistemas WindowsFile path formats on Windows systems

Los miembros de muchos de los tipos del espacio de nombres System.IO incluyen un parámetro path que permite especificar una ruta de acceso absoluta o relativa a un recurso de sistema de archivos.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. Después, esta ruta de acceso se pasa a las API del sistema de archivos de Windows.This path is then passed to Windows file system APIs. En este tema se describen los formatos de las rutas de acceso de archivo que se pueden usar en los sistemas Windows.This topic discusses the formats for file paths that you can use on Windows systems.

Rutas de acceso DOS tradicionalesTraditional DOS paths

Una ruta de acceso DOS estándar puede constar de tres componentes:A standard DOS path can consist of three components:

Si los tres componentes están presentes, la ruta de acceso es absoluta.If all three components are present, the path is absolute. Si no se especifica la letra de volumen o unidad y el nombre de directorio comienza por el carácter separador de directorio, la ruta de acceso es relativa con respecto a la raíz de la unidad actual.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. En caso contrario, la ruta de acceso es relativa al directorio actual.Otherwise, the path is relative to the current directory. En la tabla siguiente se muestran algunas rutas de acceso de directorio y archivo posibles.The following table shows some possible directory and file paths.

PathPath DescriptionDescription
C:\Documents\Newsletters\Summer2018.pdf Ruta de acceso de archivo absoluta desde la raíz de la unidad C:.An absolute file path from the root of drive C:
\Program Files\Custom Utilities\StringFinder.exe Ruta de acceso absoluta desde la raíz de la unidad actual.An absolute path from the root of the current drive.
2018\January.xlsx Ruta de acceso relativa a un archivo en un subdirectorio del directorio actual.A relative path to a file in a subdirectory of the current directory.
..\Publications\TravelBrochure.pdf Ruta de acceso relativa a un archivo en un directorio del mismo nivel del directorio actual.A relative path to file in a directory that is a peer of the current directory.
C:\Projects\apilibrary\apilibrary.sln Ruta de acceso absoluta a un archivo desde la raíz de la unidad C:An absolute path to a file from the root of drive C:
C:Projects\apilibrary\apilibrary.sln Ruta de acceso relativa desde el directorio actual de la unidad C:.A relative path from the current directory of the C: drive.

Importante

Observe la diferencia entre las dos últimas rutas de acceso.Note the difference between the last two paths. En ambas figura el especificador de volumen opcional (C: en ambos casos), pero la primera comienza por la raíz del volumen especificado, mientras que la segunda, no.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. Como resultado, la primera es una ruta de acceso absoluta desde el directorio raíz de la unidad C:, mientras que la segunda es una ruta de acceso relativa desde el directorio actual de la unidad 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:. El uso de la segunda forma cuando está previsto el de la primera suele ser motivo de errores que implican rutas de acceso de archivo de Windows.Use of the second form when the first is intended is a common source of bugs that involve Windows file paths.

Puede determinar si una ruta de acceso de archivo es un nombre completo (es decir, si la ruta de acceso es independiente del directorio actual y no cambia cuando cambia el directorio actual) mediante una llamada al 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. Tenga en cuenta que una ruta de acceso de este tipo puede incluir segmentos de directorio relativos (. y ..) y seguir siendo completa si la ruta de acceso resuelta siempre apunta a la misma ubicación.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.

En el ejemplo siguiente se muestra la diferencia entre las rutas de acceso absolutas y relativas.The following example illustrates the difference between absolute and relative paths. Se supone que existe el directorio D:\FY2018\ y que aún no ha establecido ningún directorio actual para D:\ desde el símbolo del sistema antes de ejecutar el ejemplo.It assumes that the directory D:\FY2018\ exists, and that you haven't set any current 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

Si quiere que los comentarios de código se traduzcan en más idiomas además del inglés, háganoslo saber en este problema de debate de GitHub.If you would like to see code comments translated to languages other than English, let us know in this GitHub discussion issue.

Rutas de acceso UNCUNC paths

Las rutas de acceso de convención de nomenclatura universal (UNC), que se usan para acceder a los recursos de red, tienen el formato siguiente:Universal naming convention (UNC) paths, which are used to access network resources, have the following format:

  • Un nombre de servidor o host que va precedido por \\.A server or host name, which is prefaced by \\. El nombre del servidor puede ser un nombre de equipo NetBIOS o una dirección IP o FQDN (se admiten tanto IPv4 como v6).The server name can be a NetBIOS machine name or an IP/FQDN address (IPv4 as well as v6 are supported).
  • Un nombre de recurso compartido, que se separa del nombre de host mediante \.A share name, which is separated from the host name by \. Juntos, el nombre del servidor y el del recurso compartido forman el volumen.Together, the server and share name make up the volume.
  • Un nombre de directorio.A directory name. El carácter separador de directorio separa los subdirectorios dentro de la jerarquía de directorios anidados.The directory separator character separates subdirectories within the nested directory hierarchy.
  • Un nombre de archivo opcional.An optional filename. El carácter separador de directorio separa la ruta de acceso y el nombre del archivo.The directory separator character separates the file path and the filename.

A continuación se muestran algunos ejemplos de rutas de acceso UNC:The following are some examples of UNC paths:

PathPath DescriptionDescription
\\system07\C$\ Directorio raíz de la unidad C: en system07.The root directory of the C: drive on system07.
\\Server2\Share\Test\Foo.txt El archivo Foo.txt en el directorio Test del volumen \\Server2\Share.The Foo.txt file in the Test directory of the \\Server2\Share volume.

Las rutas de acceso UNC siempre deben ser completas.UNC paths must always be fully qualified. Pueden incluir segmentos de directorio relativos (. y ..), pero estos deben formar parte de una ruta de acceso completa.They can include relative directory segments (. and ..), but these must be part of a fully qualified path. Solo puede usar rutas de acceso relativas mediante la asignación de una ruta de acceso UNC a una letra de unidad.You can use relative paths only by mapping a UNC path to a drive letter.

Rutas de acceso de dispositivo DOSDOS device paths

El sistema operativo Windows tiene un modelo de objetos unificado que apunta a todos los recursos, incluidos los archivos.The Windows operating system has a unified object model that points to all resources, including files. Estas rutas de acceso de objeto son accesibles desde la ventana de consola y se exponen a la capa de Win32 a través de una carpeta especial para vínculos simbólicos a la que se asignan las rutas de acceso DOS y UNC heredadas.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. A esta carpeta especial se accede a través de la sintaxis de ruta de acceso de dispositivo DOS, que es una de las siguientes:This special folder is accessed via the DOS device path syntax, which is one of:

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

Además de identificar una unidad por su letra de unidad, puede identificar un volumen mediante su GUID de volumen.In addition to identifying a drive by its drive letter, you can identify a volume by using its volume GUID. Esto toma la forma:This takes the form:

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

Nota

La sintaxis de ruta de acceso de dispositivo DOS es compatible con las implementaciones de .NET que se ejecutan en Windows a partir de .NET Core 1.1 y .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.

La ruta de acceso de dispositivo DOS consta de los componentes siguientes:The DOS device path consists of the following components:

  • El especificador de ruta de acceso de dispositivo (\\.\ o \\?\), que identifica la ruta de acceso como una ruta de acceso de dispositivo DOS.The device path specifier (\\.\ or \\?\), which identifies the path as a DOS device path.

    Nota

    \\?\ se admite en todas las versiones de .NET Core y en .NET Framework a partir de la versión 4.6.2.The \\?\ is supported in all versions of .NET Core and in the .NET Framework starting with version 4.6.2.

  • Un vínculo simbólico para el objeto de dispositivo "real" (C: en el caso de un nombre de unidad o Volume{b75e2c83-0000-0000-0000-602f00000000} en el caso de un identificador de volumen).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).

    El primer segmento de la ruta de acceso de dispositivo DOS, una vez que el especificador de ruta de acceso de dispositivo identifica el volumen o la unidad.The first segment of the DOS device path after the device path specifier identifies the volume or drive. (Por ejemplo, \\?\C:\ y \\.\BootPartition\).(For example, \\?\C:\ and \\.\BootPartition\.)

    Existe un vínculo específico para las UNC que, de forma lógica, se denomina UNC.There is a specific link for UNCs that is called, not surprisingly, UNC. Por ejemplo:For example:

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

    Para las UNC de dispositivo, la parte del servidor o recurso compartido forma el volumen.For device UNCs, the server/share portion forms the volume. Por ejemplo, en \\?\server1\e:\utilities\\filecomparer\, la parte del servidor o recurso compartido es server1\utilities.For example, in \\?\server1\e:\utilities\\filecomparer\, the server/share portion is server1\utilities. Esto es importante cuando se llama a un método como Path.GetFullPath(String, String) con segmentos de directorio relativos, pues nunca se puede ir más allá del volumen.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.

Por definición, las rutas de acceso de dispositivo DOS son completas.DOS device paths are fully qualified by definition. No se permiten los segmentos de directorio relativos (. y ..).Relative directory segments (. and ..) are not allowed. Los directorios actuales nunca entran en uso.Current directories never enter into their usage.

Ejemplo: formas de hacer referencia al mismo archivoExample: Ways to refer to the same file

En el ejemplo siguiente se muestran algunas formas de hacer referencia a un archivo cuando se usan las API del espacio de nombres 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. En el ejemplo se crea una instancia de un objeto FileInfo y se usan sus propiedades Name y Length para mostrar el nombre y la longitud del archivo.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

Normalización de la ruta de accesoPath normalization

Casi todas las rutas de acceso que se pasan a las API de Windows se normalizan.Almost all paths passed to Windows APIs are normalized. Durante la normalización, Windows realiza los pasos siguientes:During normalization, Windows performs the following steps:

  • Identifica la ruta de acceso.Identifies the path.
  • Aplica el directorio actual a rutas de acceso parciales (relativas).Applies the current directory to partially qualified (relative) paths.
  • Aplica formato canónico a los separadores de componentes y directorios.Canonicalizes component and directory separators.
  • Evalúa los componentes de directorio relativos (. para el directorio actual y .. para el directorio principal).Evaluates relative directory components (. for the current directory and .. for the parent directory).
  • Recorta determinados caracteres.Trims certain characters.

Esta normalización se produce de manera implícita, pero se puede realizar de forma explícita mediante una llamada al método Path.GetFullPath, que encapsula una llamada a la función 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. También se puede llamar directamente a la función GetFullPathName() de Windows mediante P/Invoke.You can also call the Windows GetFullPathName() function directly using P/Invoke.

Identificación de la ruta de accesoIdentifying the path

El primer paso de la normalización de la ruta de acceso consiste en identificar el tipo de ruta de acceso.The first step in path normalization is identifying the type of path. Las rutas de acceso se incluyen en una de estas categorías:Paths fall into one of a few categories:

  • Son rutas de acceso de dispositivo; es decir, comienzan con dos separadores y un signo de interrogación o un punto (\\? o \\.).They are device paths; that is, they begin with two separators and a question mark or period (\\? or \\.).
  • Son rutas de acceso UNC, es decir, comienzan por dos separadores sin un signo de interrogación o un punto.They are UNC paths; that is, they begin with two separators without a question mark or period.
  • Son rutas de acceso DOS completas, es decir, comienzan por una letra de unidad, un separador de volumen y un separador de componentes (C:\).They are fully qualified DOS paths; that is, they begin with a drive letter, a volume separator, and a component separator (C:\).
  • Designan un dispositivo heredado (CON, LPT1).They designate a legacy device (CON, LPT1).
  • Son relativas a la raíz de la unidad actual; es decir, comienzan con un único separador de componente (\).They are relative to the root of the current drive; that is, they begin with a single component separator (\).
  • Son relativas al directorio actual de una unidad especificada, es decir, comienzan por una letra de unidad, un separador de volumen y ningún 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:).
  • Son relativas al directorio actual, es decir, comienzan por cualquier otro elemento (temp\testfile.txt).They are relative to the current directory; that is, they begin with anything else (temp\testfile.txt).

El tipo de la ruta de acceso determina si se aplica o no un directorio actual de alguna manera.The type of the path determines whether or not a current directory is applied in some way. También determina lo que es la "raíz" de la ruta de acceso.It also determines what the "root" of the path is.

Control de dispositivos heredadosHandling legacy devices

Si la ruta de acceso es un dispositivo DOS heredado como CON, COM1 o LPT1, se convierte en una ruta de acceso de dispositivo mediante la anteposición \\.\ y se devuelve.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.

Una ruta de acceso que comienza por un nombre de dispositivo heredado se interpreta siempre como un dispositivo heredado por el 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 ejemplo la ruta de acceso de dispositivo DOS para CON.TXT es \\.\CON, y la de COM1.TXT\file1.txt es \\.\COM1.For example, the DOS device path for CON.TXT is \\.\CON, and the DOS device path for COM1.TXT\file1.txt is \\.\COM1.

Aplicación del directorio actualApplying the current directory

Si una ruta de acceso no es completa, Windows le aplica el directorio actual.If a path isn't fully qualified, Windows applies the current directory to it. El directorio actual no se aplica a las rutas de acceso de dispositivo y UNC.UNCs and device paths do not have the current directory applied. Ni tampoco una unidad completa con separador C:\.Neither does a full drive with separator C:\.

Si la ruta de acceso comienza por un único separador de componente, se aplica la unidad desde el directorio actual.If the path starts with a single component separator, the drive from the current directory is applied. Por ejemplo, si la ruta de acceso de archivo es \utilities y el directorio actual es C:\temp\, la normalización genera C:\utilities.For example, if the file path is \utilities and the current directory is C:\temp\, normalization produces C:\utilities.

Si la ruta de acceso comienza por una letra de unidad, el separador de volumen y ningún separador de componente, se aplica el último directorio actual establecido desde el shell de comandos para la unidad especificada.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. Si no se estableció el último directorio actual, solo se aplica la unidad.If the last current directory was not set, the drive alone is applied. Por ejemplo, si la ruta de acceso de archivo es D:sources, el directorio actual es C:\Documents\ y el último directorio actual en la unidad D: era D:\sources\, el resultado es 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. Estas rutas de acceso "relativas a la unidad" son un origen común de errores lógicos de programas y scripts.These "drive relative" paths are a common source of program and script logic errors. Asumir que una ruta de acceso que comienza con una letra y dos puntos no es relativa evidentemente no es correcto.Assuming that a path beginning with a letter and a colon isn't relative is obviously not correct.

Si la ruta de acceso comienza por un valor distinto de un separador, se aplican la unidad y el directorio actuales.If the path starts with something other than a separator, the current drive and current directory are applied. Por ejemplo, si la ruta de acceso es filecompare y el directorio actual es C:\utilities\, el resultado es C:\utilities\filecompare\.For example, if the path is filecompare and the current directory is C:\utilities\, the result is C:\utilities\filecompare\.

Importante

El uso de rutas de acceso relativas en las aplicaciones multiproceso (es decir, en la mayoría de aplicaciones) es peligroso, porque el directorio actual es un valor de cada proceso.Relative paths are dangerous in multithreaded applications (that is, most applications) because the current directory is a per-process setting. Cualquier subproceso puede cambiar el directorio actual en cualquier momento.Any thread can change the current directory at any time. A partir de .NET Core 2.1, se puede llamar al método Path.GetFullPath(String, String) para obtener una ruta de acceso absoluta a partir de una ruta de acceso relativa y la ruta de acceso base (el directorio actual) sobre la que se quiere resolver.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.

Asignación canónica de separadoresCanonicalizing separators

Todas las barras diagonales (/) se convierten en el separador estándar de Windows, que es la barra diagonal inversa (\).All forward slashes (/) are converted into the standard Windows separator, the back slash (\). Si están presentes, una serie de barras diagonales que siguen a las dos primeras barras diagonales se contraen en una sola barra diagonal.If they are present, a series of slashes that follow the first two slashes are collapsed into a single slash.

Evaluación de componentes relativosEvaluating relative components

Cuando se procesa la ruta de acceso, se evalúan los componentes o segmentos que se componen de un punto o un punto doble (. o ..):As the path is processed, any components or segments that are composed of a single or a double period (. or ..) are evaluated:

  • Para un punto, se quita el segmento actual, ya que hace referencia al directorio actual.For a single period, the current segment is removed, since it refers to the current directory.

  • Para un punto doble, se quitan el segmento actual y el principal, ya que el punto doble hace referencia al directorio principal.For a double period, the current segment and the parent segment are removed, since the double period refers to the parent directory.

    Los directorios principales solo se quitan si no están después de la raíz de la ruta de acceso.Parent directories are only removed if they aren't past the root of the path. La raíz de la ruta de acceso depende del tipo de ruta de acceso.The root of the path depends on the type of path. Es la unidad (C:\) para las rutas de acceso DOS, el servidor o recurso compartido para las UNC (\\Server\Share), y el prefijo de ruta de acceso de dispositivo para las rutas de acceso de dispositivo (\\?\ o \\.\).It is the drive (C:\) for DOS paths, the server/share for UNCs (\\Server\Share), and the device path prefix for device paths (\\?\ or \\.\).

Recorte de caracteresTrimming characters

Junto con las ejecuciones de los separadores y segmentos relativos que se han quitado anteriormente, durante la normalización se quitan algunos caracteres adicionales:Along with the runs of separators and relative segments removed earlier, some additional characters are removed during normalization:

  • Si un segmento termina en un punto, se quita ese punto.If a segment ends in a single period, that period is removed. (Un segmento de un punto o un punto doble se normaliza en el paso anterior.(A segment of a single or double period is normalized in the previous step. Un segmento de tres o más puntos no se normaliza y, en realidad, es un nombre de archivo o directorio válido).A segment of three or more periods is not normalized and is actually a valid file/directory name.)

  • Si la ruta de acceso no termina en un separador, se quitan todos los puntos y espacios finales (U+0020).If the path doesn't end in a separator, all trailing periods and spaces (U+0020) are removed. Si el último segmento es simplemente un punto o un punto doble, se aplica la regla anterior de componentes relativos.If the last segment is simply a single or double period, it falls under the relative components rule above.

    Esta regla significa que se puede crear un nombre de directorio con un espacio final si se agrega un separador final después del espacio.This rule means that you can create a directory name with a trailing space by adding a trailing separator after the space.

    Importante

    Nunca se debe crear un nombre de archivo o directorio con un espacio final.You should never create a directory or filename with a trailing space. Los espacios finales pueden dificultar o impedir el acceso a un directorio, y se suelen producir errores en las aplicaciones cuando se intenta controlar directorios o archivos con nombres que incluyen espacios.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.

Omisión de la normalizaciónSkipping normalization

Normalmente, todas las rutas de acceso que se pasan a una API de Windows se pasan (de forma efectiva) a la función GetFullPathName y se normalizan.Normally, any path passed to a Windows API is (effectively) passed to the GetFullPathName function and normalized. Hay una excepción importante: una ruta de acceso de dispositivo que comienza con un signo de interrogación en lugar de un punto.There is one important exception: a device path that begins with a question mark instead of a period. A menos que la ruta de acceso comience exactamente con \\?\ (observe el uso de la barra diagonal inversa canónica), se normaliza.Unless the path starts exactly with \\?\ (note the use of the canonical backslash), it is normalized.

¿Por qué querría omitir la normalización?Why would you want to skip normalization? Hay tres razones principales:There are three major reasons:

  1. Para obtener acceso a las rutas de acceso que normalmente no están disponibles pero que son válidas.To get access to paths that are normally unavailable but are legal. A un archivo o directorio denominado hidden., por ejemplo, no se puede acceder de otra forma.A file or directory called hidden., for example, is impossible to access in any other way.

  2. Para mejorar el rendimiento omitiendo la normalización, si ya se ha normalizado.To improve performance by skipping normalization if you've already normalized.

  3. Solo en .NET Framework, para omitir la comprobación MAX_PATH de la longitud de ruta de acceso para permitir rutas de acceso que tienen más 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. En la mayoría de API se permite esto, con algunas excepciones.Most APIs allow this, with some exceptions.

Nota

En .NET Core las rutas de acceso largas se administran de forma implícita y no se realiza una comprobación MAX_PATH..NET Core handles long paths implicitly and does not perform a MAX_PATH check. La comprobación MAX_PATH solo se aplica a .NET Framework.The MAX_PATH check applies only to the .NET Framework.

La omisión de la normalización y las comprobaciones de ruta de acceso máximas es la única diferencia entre las dos sintaxis de ruta de acceso de dispositivo. En los demás casos son idénticas.Skipping normalization and max path checks is the only difference between the two device path syntaxes; they are otherwise identical. Tenga cuidado al omitir la normalización, dado que es muy fácil crear rutas de acceso difíciles de controlar para las aplicaciones "normales".Be careful with skipping normalization, since you can easily create paths that are difficult for "normal" applications to deal with.

Las rutas de acceso que empiezan por \\?\ se siguen normalizando si se pasan de forma explícita a la función GetFullPathName.Paths that start with \\?\ are still normalized if you explicitly pass them to the GetFullPathName function.

Puede pasar rutas de acceso de más de MAX_PATH caracteres a GetFullPathName sin \\?\.You can pass paths of more than MAX_PATH characters to GetFullPathName without \\?\. Admite rutas de acceso de longitud arbitraria hasta el tamaño de cadena máximo admitido por Windows.It supports arbitrary length paths up to the maximum string size that Windows can handle.

Las mayúsculas y minúsculas y el sistema de archivos de WindowsCase and the Windows file system

Una peculiaridad del sistema de archivos de Windows que resulta confuso para los usuarios y desarrolladores que no usan Windows es que los nombres de ruta de acceso y directorio no distinguen mayú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. Es decir, los nombres de archivos y directorios reflejan las mayúsculas y minúsculas de las cadenas que se usan cuando se crean.That is, directory and file names reflect the casing of the strings used when they are created. Por ejemplo, la llamada al métodoFor example, the method call

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

crea un directorio denominado TeStDiReCtOrY.creates a directory named TeStDiReCtOrY. Si modifica el nombre de un directorio o archivo para cambiar sus mayúsculas y minúsculas, el nombre del directorio o archivo refleja las mayúsculas y minúsculas de la cadena usada al cambiar el nombre.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 ejemplo, en el código siguiente se cambia el nombre de un archivo de test.txt a 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

Pero las comparaciones de nombre de directorio y archivo no distinguen mayúsculas de minúsculas.However, directory and file name comparisons are case-insensitive. Si busca un archivo denominado "test.txt", las API del sistema de archivos de .NET ignoran las mayúsculas y minúsculas en la comparación.If you search for a file named "test.txt", .NET file system APIs ignore case in the comparison. Test.txt, TEST.TXT, test.TXT y cualquier otra combinación de letras mayúsculas y minúsculas coincidirán con "test.txt".Test.txt, TEST.TXT, test.TXT, and any other combination of upper- and lowercase letters will match "test.txt".