without fullpath filename extension combine c# .net filepath

c# - fullpath - ¿Cómo puedo obtener la ruta que distingue entre mayúsculas y minúsculas en Windows?



path combine c# (7)

Necesito saber cuál es el camino real de un camino determinado.

Por ejemplo:

La ruta real es: d: / src / File.txt
Y el usuario me da: D: / src / file.txt
Necesito como resultado: d: / src / File.txt


Aquí hay una solución alternativa, funciona en archivos y directorios. Utiliza GetFinalPathNameByHandle, que solo es compatible con aplicaciones de escritorio en Vista / Server2008 o superior según los documentos.

Tenga en cuenta que resolverá un enlace simbólico si le da uno, que es parte de encontrar la ruta "final".

// http://www.pinvoke.net/default.aspx/shell32/GetFinalPathNameByHandle.html [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint GetFinalPathNameByHandle(SafeFileHandle hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags); private const uint FILE_NAME_NORMALIZED = 0x0; static string GetFinalPathNameByHandle(SafeFileHandle fileHandle) { StringBuilder outPath = new StringBuilder(1024); var size = GetFinalPathNameByHandle(fileHandle, outPath, (uint)outPath.Capacity, FILE_NAME_NORMALIZED); if (size == 0 || size > outPath.Capacity) throw new Win32Exception(Marshal.GetLastWin32Error()); // may be prefixed with //?/, which we don''t want if (outPath[0] == ''//' && outPath[1] == ''//' && outPath[2] == ''?'' && outPath[3] == ''//') return outPath.ToString(4, outPath.Length - 4); return outPath.ToString(); } // http://www.pinvoke.net/default.aspx/kernel32.createfile [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern SafeFileHandle CreateFile( [MarshalAs(UnmanagedType.LPTStr)] string filename, [MarshalAs(UnmanagedType.U4)] FileAccess access, [MarshalAs(UnmanagedType.U4)] FileShare share, IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, IntPtr templateFile); private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; public static string GetFinalPathName(string dirtyPath) { // use 0 for access so we can avoid error on our metadata-only query (see dwDesiredAccess docs on CreateFile) // use FILE_FLAG_BACKUP_SEMANTICS for attributes so we can operate on directories (see Directories in remarks section for CreateFile docs) using (var directoryHandle = CreateFile( dirtyPath, 0, FileShare.ReadWrite | FileShare.Delete, IntPtr.Zero, FileMode.Open, (FileAttributes)FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero)) { if (directoryHandle.IsInvalid) throw new Win32Exception(Marshal.GetLastWin32Error()); return GetFinalPathNameByHandle(directoryHandle); } }


Como la respuesta de Borja no funciona para volúmenes en los que los nombres 8.3 están deshabilitados, aquí la implementación recursiva que sugiere Tergiver (funciona para archivos y carpetas, así como los archivos y carpetas de recursos compartidos UNC pero no en sus nombres de máquinas ni en sus nombres compartidos).

Los archivos o carpetas no existentes no son un problema, lo que existe se verifica y se corrige, pero es posible que tenga problemas de redirección de carpetas, por ejemplo, al intentar obtener la ruta correcta de "C: / WinDoWs / sYsteM32 / driVErs / eTC / Hosts" obtendrá "C: / Windows / System32 / drivers / eTC / hosts" en una ventana de 64 bits, ya que no hay una carpeta "etc" con "C: / Windows / sysWOW64 / drivers".

Escenario de prueba:

Directory.CreateDirectory(@"C:/Temp/SomeFolder"); File.WriteAllLines(@"C:/Temp/SomeFolder/MyTextFile.txt", new String[] { "Line1", "Line2" });

Uso:

FileInfo myInfo = new FileInfo(@"C:/TEMP/SOMEfolder/MyTeXtFiLe.TxT"); String myResult = myInfo.GetFullNameWithCorrectCase(); //Returns "C:/Temp/SomeFolder/MyTextFile.txt"

Código:

public static class FileSystemInfoExt { public static String GetFullNameWithCorrectCase(this FileSystemInfo fileOrFolder) { //Check whether null to simulate instance method behavior if (Object.ReferenceEquals(fileOrFolder, null)) throw new NullReferenceException(); //Initialize common variables String myResult = GetCorrectCaseOfParentFolder(fileOrFolder.FullName); return myResult; } private static String GetCorrectCaseOfParentFolder(String fileOrFolder) { String myParentFolder = Path.GetDirectoryName(fileOrFolder); String myChildName = Path.GetFileName(fileOrFolder); if (Object.ReferenceEquals(myParentFolder, null)) return fileOrFolder.TrimEnd(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); if (Directory.Exists(myParentFolder)) { //myParentFolder = GetLongPathName.Invoke(myFullName); String myFileOrFolder = Directory.GetFileSystemEntries(myParentFolder, myChildName).FirstOrDefault(); if (!Object.ReferenceEquals(myFileOrFolder, null)) { myChildName = Path.GetFileName(myFileOrFolder); } } return GetCorrectCaseOfParentFolder(myParentFolder) + Path.DirectorySeparatorChar + myChildName; } }


Como veterano, siempre usé FindFirstFile para este propósito. La traducción .Net es:

Directory.GetFiles(Path.GetDirectoryName(userSuppliedName), Path.GetFileName(userSuppliedName)).FirstOrDefault();

Esto solo le proporciona la carcasa correcta para la parte del nombre de archivo de la ruta, no la ruta completa.

El comentario de JeffreyLWhitledge proporciona un enlace a una versión recursiva que puede funcionar (aunque no siempre) para resolver la ruta completa.


En Windows, las rutas son sensibles a mayúsculas y minúsculas. Así que ambos caminos son igualmente reales.

Si desea obtener algún tipo de ruta con mayúscula canónica (es decir, cómo piensa Windows que debería estar en mayúscula), puede llamar a FindFirstFile () con la ruta como una máscara, luego tomar el nombre completo del archivo encontrado. Si la ruta no es válida, entonces no obtendrá un nombre canónico, de forma nativa.


La forma de obtener la ruta real de un archivo (esto no funcionará para las carpetas) es seguir estos pasos:

  1. Llame a CreateFileMapping para crear una asignación para el archivo.
  2. Llame a GetMappedFileName para obtener el nombre del archivo.
  3. Use QueryDosDevice para convertirlo en un nombre de ruta de estilo de MS-DOS.

Si tienes ganas de escribir un programa más robusto que también funciona con directorios (pero con más dolor y algunas características no documentadas), sigue estos pasos:

  1. Obtenga un identificador para el archivo / carpeta con NtOpenFile o NtOpenFile .
  2. Llame a NtQueryObject para obtener el nombre completo de la ruta.
  3. Llame a NtQueryInformationFile con FileNameInformation para obtener la ruta relativa al volumen.
  4. Utilizando las dos rutas anteriores, obtenga el componente de la ruta que representa el volumen en sí. Por ejemplo, si obtiene /Device/HarddiskVolume1/Hello.txt para la primera ruta y /Hello.txt para la segunda, ahora sabe que la ruta del volumen es /Device/HarddiskVolume1 .
  5. Utilice los códigos de control de E / S de Mount Manager o el QueryDosDevice mal documentados para convertir la parte del volumen de la ruta completa de estilo NT con la letra de la unidad.

Ahora tienes la ruta real del archivo.


Puede utilizar esta función:

[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)] static extern uint GetLongPathName(string ShortPath, StringBuilder sb, int buffer); [DllImport("kernel32.dll")] static extern uint GetShortPathName(string longpath, StringBuilder sb, int buffer); protected static string GetWindowsPhysicalPath(string path) { StringBuilder builder = new StringBuilder(255); // names with long extension can cause the short name to be actually larger than // the long name. GetShortPathName(path, builder, builder.Capacity); path = builder.ToString(); uint result = GetLongPathName(path, builder, builder.Capacity); if (result > 0 && result < builder.Capacity) { //Success retrieved long file name builder[0] = char.ToLower(builder[0]); return builder.ToString(0, (int)result); } if (result > 0) { //Need more capacity in the buffer //specified in the result variable builder = new StringBuilder((int)result); result = GetLongPathName(path, builder, builder.Capacity); builder[0] = char.ToLower(builder[0]); return builder.ToString(0, (int)result); } return null; }


Solución alternativa

Aquí hay una solución que me sirvió para mover archivos entre Windows y un servidor mediante rutas sensibles a mayúsculas. GetFileSystemEntries() el árbol del directorio y corrige cada entrada con GetFileSystemEntries() . Si parte de la ruta no es válida (UNC o nombre de carpeta), corrige la ruta solo hasta ese punto y luego usa la ruta original para lo que no puede encontrar. De todos modos, espero que esto ahorre a los demás tiempo al tratar el mismo problema.

private string GetCaseSensitivePath(string path) { var root = Path.GetPathRoot(path); try { foreach (var name in path.Substring(root.Length).Split(Path.DirectorySeparatorChar)) root = Directory.GetFileSystemEntries(root, name).First(); } catch (Exception e) { // Log("Path not found: " + path); root += path.Substring(root.Length); } return root; }