c# - getfilename - ¿Cómo garantizar que haya un separador de directorios posterior en las rutas?
relative path c# (4)
Tengo un problema con AppDomain.CurrentDomain.BaseDirectory
.
A veces el camino termina con ''/' y otras veces no. No puedo encontrar una razón para esto.
Estaría bien si estuviera usando Path.Combine
pero quiero hacer Directory.GetParent
y arroja resultados diferentes.
¿Has encontrado este problema?
¿Puedo hacer las cosas de manera diferente para obtener el directorio principal de la aplicación?
Mi hack actual es:
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
if (!baseDir.EndsWith("//")) baseDir += "//";
A menudo uso
path = Path.Combine(path, "x");
path = path.Substring(0, path.Length - 1);
O, si lo necesitaba más de una o dos veces en el mismo proyecto, probablemente usaría una función auxiliar como esta:
string EnsureTerminatingDirectorySeparator(string path)
{
if (path == null)
throw new ArgumentNullException("path");
int length = path.Length;
if (length == 0)
return "." + Path.DirectorySeparatorChar;
char lastChar = path[length - 1];
if (lastChar == Path.DirectorySeparatorChar || lastChar == Path.AltDirectorySeparatorChar)
return path;
int lastSep = path.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
if (lastSep >= 0)
return path + path[lastSep];
else
return path + Path.DirectorySeparatorChar;
}
Es así, solo mantén tu truco.
En Win32 simple hay una función auxiliar PathAddBackslash para eso. Simplemente sea coherente con el separador de directorios: marque Path.DirectorySeparatorChar
y Path.AltDirectorySeparatorChar
lugar de hard-code /
.
Algo como esto (tenga en cuenta que no hay una comprobación de error grave):
string PathAddBackslash(string path)
{
// They''re always one character but EndsWith is shorter than
// array style access to last path character. Change this
// if performance are a (measured) issue.
string separator1 = Path.DirectorySeparatorChar.ToString();
string separator2 = Path.AltDirectorySeparatorChar.ToString();
// Trailing white spaces are always ignored but folders may have
// leading spaces. It''s unusual but it may happen. If it''s an issue
// then just replace TrimEnd() with Trim(). Tnx Paul Groke to point this out.
path = path.TrimEnd();
// Argument is always a directory name then if there is one
// of allowed separators then I have nothing to do.
if (path.EndsWith(separator1) || path.EndsWith(separator2))
return path;
// If there is the "alt" separator then I add a trailing one.
// Note that URI format (file://drive:/path/filename.ext) is
// not supported in most .NET I/O functions then we don''t support it
// here too. If you have to then simply revert this check:
// if (path.Contains(separator1))
// return path + separator1;
//
// return path + separator2;
if (path.Contains(separator2))
return path + separator2;
// If there is not an "alt" separator I add a "normal" one.
// It means path may be with normal one or it has not any separator
// (for example if it''s just a directory name). In this case I
// default to normal as users expect.
return path + separator1;
}
¿Por qué tanto código? Principal porque si el usuario ingresa /windows/system32
no quiere obtener /windows/system32/
pero /windows/system32/
, el diablo está en los detalles ...
Para poner todo junto en una forma mejor auto-explicativa:
string PathAddBackslash(string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
path = path.TrimEnd();
if (PathEndsWithDirectorySeparator())
return path;
return path + GetDirectorySeparatorUsedInPath();
bool PathEndsWithDirectorySeparator()
{
if (path.Length == 0)
return false;
char lastChar = path[path.Length - 1];
return lastChar == Path.DirectorySeparatorChar
|| lastChar == Path.AltDirectorySeparatorChar;
}
char GetDirectorySeparatorUsedInPath()
{
if (path.Contains(Path.AltDirectorySeparatorChar))
return Path.AltDirectorySeparatorChar;
return Path.DirectorySeparatorChar;
}
}
El file://
formato URI file://
no se maneja aunque parezca así. Lo correcto es volver a hacer lo que hacen las otras funciones de E / S .NET: no maneje este formato (y posiblemente genere una excepción).
Como alternativa, siempre puedes importar la función Win32:
[DllImport("shlwapi.dll",
EntryPoint = "PathAddBackslashW",
SetLastError = True,
CharSet = CharSet.Unicode)]
static extern IntPtr PathAddBackslash(
[MarshalAs(UnmanagedType.LPTStr)]StringBuilder lpszPath);
Para obtener soporte multiplataforma, puede usar este fragmento:
using System.IO;
// Your input string.
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
// Get the absolut path from it (in case ones input is a relative path).
string fullPath = Path.GetFullPath(baseDir);
// Check for ending slashes, remove them (if any)
// and add a cross platform slash at the end.
string result = fullPath
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ Path.DirectorySeparatorChar;
Como un método:
private static string GetFullPathWithEndingSlashes(string input)
{
string fullPath = Path.GetFullPath(input);
return fullPath
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ Path.DirectorySeparatorChar;
}
O como un método de extensión:
public static string GetFullPathWithEndingSlashes(this string input)
{
return Path.GetFullPath(input)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ Path.DirectorySeparatorChar;
}
Puede garantizar fácilmente el comportamiento que desea utilizando TrimEnd :
var baseDir = AppDomain.CurrentDomain.BaseDirectory.TrimEnd(''//') + "//";
Para ser eficiente de manera óptima (evitando asignaciones adicionales), verifique que la cadena no termine con un /
antes de realizar cambios, ya que no siempre será necesario:
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
if (!baseDir.EndsWith("//"))
{
baseDir += "//";
}