net libreria info extension example delete c# .net file

info - libreria system.io en c#



¿Por qué Path.Combine no concatena adecuadamente los nombres de archivo que comienzan con Path.DirectorySeparatorChar? (13)

Desde la ventana Inmediato en Visual Studio:

> Path.Combine(@"C:/x", "y") "C://x//y" > Path.Combine(@"C:/x", @"/y") "//y"

Parece que ambos deberían ser lo mismo.

El antiguo FileSystemObject.BuildPath () no funcionaba de esta manera ...


Al no conocer los detalles reales, supongo que intenta unirse como si se uniera a URI relativos. Por ejemplo:

urljoin(''/some/abs/path'', ''../other'') = ''/some/abs/other''

Esto significa que cuando se une a una ruta con una barra oblicua anterior, en realidad está uniendo una base con otra, en cuyo caso la segunda tiene prioridad.


Desde MSDN :

Si una de las rutas especificadas es una cadena de longitud cero, este método devuelve la otra ruta. Si path2 contiene una ruta absoluta, este método devuelve path2.

En tu ejemplo, path2 es absoluto.


En mi opinión, esto es un error. El problema es que hay dos tipos diferentes de rutas "absolutas". La ruta "d: / mydir / myfile.txt" es absoluta, la ruta "/ mydir / myfile.txt" también se considera "absoluta" aunque falte la letra de la unidad. El comportamiento correcto, en mi opinión, sería anteponer la letra de la unidad de la primera ruta cuando la segunda ruta comience con el separador de directorio (y no sea una ruta UNC). Te recomendaría escribir tu propia función de envoltura auxiliar que tenga el comportamiento que deseas si la necesitas.


Esta es una especie de pregunta filosófica (que quizás solo Microsoft realmente pueda responder), ya que está haciendo exactamente lo que dice la documentación.

System.IO.Path.Combine

"Si path2 contiene una ruta absoluta, este método devuelve path2".

Aquí está el método de combinación real de la fuente de .NET. Puede ver que llama a CombineNoChecks , que luego llama a IsPathRooted en path2 y devuelve esa ruta si es así.

No sé cuál es el fundamento. Supongo que la solución es quitar (o recortar) DirectorySeparatorChar desde el comienzo de la segunda ruta; quizás escriba su propio método Combine que hace eso y luego llama a Path.Combine ().


Este código debería hacer el truco:

string strFinalPath = string.Empty; string normalizedFirstPath = Path1.TrimEnd(new char[] { ''//' }); string normalizedSecondPath = Path2.TrimStart(new char[] { ''//' }); strFinalPath = Path.Combine(normalizedFirstPath, normalizedSecondPath); return strFinalPath;


Este es el código desensamblado del reflector .NET para el método Path.Combine. Compruebe la función IsPathRooted. Si la segunda ruta está rooteada (comienza con un DirectorySeparatorChar), regrese la segunda ruta como está.

public static string Combine(string path1, string path2) { if ((path1 == null) || (path2 == null)) { throw new ArgumentNullException((path1 == null) ? "path1" : "path2"); } CheckInvalidPathChars(path1); CheckInvalidPathChars(path2); if (path2.Length == 0) { return path1; } if (path1.Length == 0) { return path2; } if (IsPathRooted(path2)) { return path2; } char ch = path1[path1.Length - 1]; if (((ch != DirectorySeparatorChar) && (ch != AltDirectorySeparatorChar)) && (ch != VolumeSeparatorChar)) { return (path1 + DirectorySeparatorChar + path2); } return (path1 + path2); } public static bool IsPathRooted(string path) { if (path != null) { CheckInvalidPathChars(path); int length = path.Length; if ( ( (length >= 1) && ( (path[0] == DirectorySeparatorChar) || (path[0] == AltDirectorySeparatorChar) ) ) || ((length >= 2) && (path[1] == VolumeSeparatorChar)) ) { return true; } } return false; }


Esto / significa "el directorio raíz de la unidad actual". En su ejemplo, significa la carpeta "prueba" en el directorio raíz de la unidad actual. Entonces, esto puede ser igual a "c: / test"


Esto realmente tiene sentido, de alguna manera, teniendo en cuenta cómo se tratan los caminos (relativos) por lo general:

string GetFullPath(string path) { string baseDir = @"C:/Users/Foo.Bar"; return Path.Combine(baseDir, path); } // get full path for RELATIVE file path GetFullPath("file.txt"); // = C:/Users/Foo.Bar/file.txt // get full path for ROOTED file path GetFullPath(@"C:/Temp/file.txt"); // = C:/Temp/file.txt

La verdadera pregunta es por qué las rutas que comienzan con "/" consideran "rooteadas". Esto era nuevo para mí, pero funciona de esa manera en Windows :

new FileInfo("/windows"); // FullName = C:/Windows, Exists = True new FileInfo("windows"); // FullName = C:/Users/Foo.Bar/Windows, Exists = False


Estos dos métodos deberían evitar que accidentalmente una dos cadenas que tengan el delimitador en ellas.

public static string Combine(string x, string y, char delimiter) { return $"{ x.TrimEnd(delimiter) }{ delimiter }{ y.TrimStart(delimiter) }"; } public static string Combine(string[] xs, char delimiter) { if (xs.Length < 1) return string.Empty; if (xs.Length == 1) return xs[0]; var x = Combine(xs[0], xs[1], delimiter); if (xs.Length == 2) return x; var ys = new List<string>(); ys.Add(x); ys.AddRange(xs.Skip(2).ToList()); return Combine(ys.ToArray(), delimiter); }


Ok, ya hay una larga lista de respuestas, aquí está la mía ;-)

Yo quería resolver este problema:

string sample1 = "configuration/config.xml"; string sample2 = "/configuration/config.xml"; string sample3 = "//configuration/config.xml"; string dir1 = "c://temp"; string dir2 = "c://temp//"; string dir3 = "c://temp/"; string path1 = PathCombine(dir1, sample1); string path2 = PathCombine(dir1, sample2); string path3 = PathCombine(dir1, sample3); string path4 = PathCombine(dir2, sample1); string path5 = PathCombine(dir2, sample2); string path6 = PathCombine(dir2, sample3); string path7 = PathCombine(dir3, sample1); string path8 = PathCombine(dir3, sample2); string path9 = PathCombine(dir3, sample3);

Por supuesto, todas las pathes 1-9 deben contener una cadena equivalente al final. Aquí está el método PathCombine que se me ocurrió:

private string PathCombine(string path1, string path2) { if (Path.IsPathRooted(path2)) { path2 = path2.TrimStart(Path.DirectorySeparatorChar); path2 = path2.TrimStart(Path.AltDirectorySeparatorChar); } return Path.Combine(path1, path2); }

También creo que es bastante molesto que este manejo de cadenas se haga manualmente, me interesaría la razón detrás de esto.


Si desea combinar ambas rutas sin perder ninguna ruta, puede usar esto:

?Path.Combine(@"C:/test", @"/test".Substring(0, 1) == @"/" ? @"/test".Substring(1, @"/test".Length - 1) : @"/test");

O con variables:

string Path1 = @"C:/Test"; string Path2 = @"/test"; string FullPath = Path.Combine(Path1, Path2.Substring(0, 1) == @"/" ? Path2.Substring(1, Path2.Length - 1) : Path2);

Ambos casos devuelven "C: / prueba / prueba".

Primero, evalúo si Path2 comienza con / y si es verdadero, devuelve Path2 sin el primer caracter. De lo contrario, devuelve Path2 completo.


Siguiendo el consejo de Christian Graus en su blog "Cosas que odio sobre Microsoft" titulado " Path.Combine es esencialmente inútil ", esta es mi solución:

public static class Pathy { public static string Combine(string path1, string path2) { if (path1 == null) return path2 else if (path2 == null) return path1 else return path1.Trim().TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar + path2.Trim().TrimStart(System.IO.Path.DirectorySeparatorChar); } public static string Combine(string path1, string path2, string path3) { return Combine(Combine(path1, path2), path3); } }

Algunos aconsejan que los espacios de nombres colisionen, ... Fui con Pathy , como un ligero, y para evitar la colisión del espacio de nombres con System.IO.Path .

Editar : se agregaron verificaciones de parámetros nulos


Motivo: su segunda URL se considera una ruta absoluta, el método Combine solo devolverá la última ruta si la última ruta es una ruta absoluta.

Solución: simplemente elimine la barra inicial / de su segunda ruta. ( /SecondPath a SecondPath ). entonces funciona como usted exceptuó.