ruta getfilename current combine c# string path directory

current - path getfilename c#



¿Cómo eliminar los caracteres ilegales de la ruta y los nombres de archivo? (25)

Necesito una forma robusta y sencilla de eliminar la ruta y los caracteres ilegales de una cadena simple. He usado el código de abajo pero no parece hacer nada, ¿qué me estoy perdiendo?

using System; using System.IO; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string illegal = "/"M<>/"//a/ry/ h**ad:>> a///:*?/"<>| li*tt|le|| la/"mb.?"; illegal = illegal.Trim(Path.GetInvalidFileNameChars()); illegal = illegal.Trim(Path.GetInvalidPathChars()); Console.WriteLine(illegal); Console.ReadLine(); } } }


Aquí hay un fragmento de código que debería ayudar para .NET 3 y superior.

using System.IO; using System.Text.RegularExpressions; public static class PathValidation { private static string pathValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]+$"; private static Regex pathValidator = new Regex(pathValidatorExpression, RegexOptions.Compiled); private static string fileNameValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]+$"; private static Regex fileNameValidator = new Regex(fileNameValidatorExpression, RegexOptions.Compiled); private static string pathCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]"; private static Regex pathCleaner = new Regex(pathCleanerExpression, RegexOptions.Compiled); private static string fileNameCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]"; private static Regex fileNameCleaner = new Regex(fileNameCleanerExpression, RegexOptions.Compiled); public static bool ValidatePath(string path) { return pathValidator.IsMatch(path); } public static bool ValidateFileName(string fileName) { return fileNameValidator.IsMatch(fileName); } public static string CleanPath(string path) { return pathCleaner.Replace(path, ""); } public static string CleanFileName(string fileName) { return fileNameCleaner.Replace(fileName, ""); } }


Creé un método de extensión que combina varias sugerencias:

  1. Mantener personajes ilegales en un conjunto de hash
  2. Filtrado de caracteres por debajo de ascii 127. Ya que Path.GetInvalidFileNameChars no incluye todos los caracteres no válidos posibles con los códigos ascii de 0 a 255. Consulte aquí y MSDN
  3. Posibilidad de definir el carácter de reemplazo.

Fuente:

public static class FileNameCorrector { private static HashSet<char> invalid = new HashSet<char>(Path.GetInvalidFileNameChars()); public static string ToValidFileName(this string name, char replacement = ''/0'') { var builder = new StringBuilder(); foreach (var cur in name) { if (cur > 31 && cur < 128 && !invalid.Contains(cur)) { builder.Append(cur); } else if (replacement != ''/0'') { builder.Append(replacement); } } return builder.ToString(); } }


Creo que es mucho más fácil validar usando una expresión regular y especificando qué caracteres están permitidos, en lugar de intentar verificar todos los caracteres incorrectos. Consulte estos enlaces: http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

Además, haz una búsqueda de "editores de expresiones regulares", te ayudan mucho. Hay algunos en torno a los cuales incluso se imprime el código en c # para ti.


Creo que la pregunta ya no está completa. Las respuestas solo describen el nombre de archivo limpio O la ruta ... no ambas. Aquí está mi solución:

private static string CleanPath(string path) { string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch))); List<string> split = path.Split(''//').ToList(); string returnValue = split.Aggregate(string.Empty, (current, s) => current + (r.Replace(s, "") + @"/")); returnValue = returnValue.TrimEnd(''//'); return returnValue; }


El nombre del archivo no puede contener caracteres de Path.GetInvalidPathChars() , símbolos + y # , y otros nombres específicos. Combinamos todos los cheques en una clase:

public static class FileNameExtensions { private static readonly Lazy<string[]> InvalidFileNameChars = new Lazy<string[]>(() => Path.GetInvalidPathChars() .Union(Path.GetInvalidFileNameChars() .Union(new[] { ''+'', ''#'' })).Select(c => c.ToString(CultureInfo.InvariantCulture)).ToArray()); private static readonly HashSet<string> ProhibitedNames = new HashSet<string> { @"aux", @"con", @"clock$", @"nul", @"prn", @"com1", @"com2", @"com3", @"com4", @"com5", @"com6", @"com7", @"com8", @"com9", @"lpt1", @"lpt2", @"lpt3", @"lpt4", @"lpt5", @"lpt6", @"lpt7", @"lpt8", @"lpt9" }; public static bool IsValidFileName(string fileName) { return !string.IsNullOrWhiteSpace(fileName) && fileName.All(o => !IsInvalidFileNameChar(o)) && !IsProhibitedName(fileName); } public static bool IsProhibitedName(string fileName) { return ProhibitedNames.Contains(fileName.ToLower(CultureInfo.InvariantCulture)); } private static string ReplaceInvalidFileNameSymbols([CanBeNull] this string value, string replacementValue) { if (value == null) { return null; } return InvalidFileNameChars.Value.Aggregate(new StringBuilder(value), (sb, currentChar) => sb.Replace(currentChar, replacementValue)).ToString(); } public static bool IsInvalidFileNameChar(char value) { return InvalidFileNameChars.Value.Contains(value.ToString(CultureInfo.InvariantCulture)); } public static string GetValidFileName([NotNull] this string value) { return GetValidFileName(value, @"_"); } public static string GetValidFileName([NotNull] this string value, string replacementValue) { if (string.IsNullOrWhiteSpace(value)) { throw new ArgumentException(@"value should be non empty", nameof(value)); } if (IsProhibitedName(value)) { return (string.IsNullOrWhiteSpace(replacementValue) ? @"_" : replacementValue) + value; } return ReplaceInvalidFileNameSymbols(value, replacementValue); } public static string GetFileNameError(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { return CommonResources.SelectReportNameError; } if (IsProhibitedName(fileName)) { return CommonResources.FileNameIsProhibited; } var invalidChars = fileName.Where(IsInvalidFileNameChar).Distinct().ToArray(); if(invalidChars.Length > 0) { return string.Format(CultureInfo.CurrentCulture, invalidChars.Length == 1 ? CommonResources.InvalidCharacter : CommonResources.InvalidCharacters, StringExtensions.JoinQuoted(@",", @"''", invalidChars.Select(c => c.ToString(CultureInfo.CurrentCulture)))); } return string.Empty; } }

El método GetValidFileName reemplaza todos los datos incorrectos a _ .


Escaneando las respuestas aquí, todas ** parecen involucrar el uso de una matriz de caracteres de caracteres inválidos.

Por supuesto, esto puede ser una optimización micro, pero para el beneficio de cualquier persona que esté buscando verificar una gran cantidad de valores para que sean nombres de archivo válidos, vale la pena señalar que crear un hashset de caracteres no válidos producirá un rendimiento notablemente mejor.

En el pasado, me sorprendió (sorprendió) la rapidez con la que un hashset (o diccionario) supera la iteración de una lista. Con cadenas, es un número ridículamente bajo (alrededor de 5-7 elementos de la memoria). Con la mayoría de los otros datos simples (referencias de objetos, números, etc.) el cruce mágico parece ser alrededor de 20 elementos.

Hay 40 caracteres no válidos en la "lista" de Path.InvalidFileNameChars. Hice una búsqueda hoy y hay un buen punto de referencia aquí en que muestra que el hashset tomará un poco más de la mitad del tiempo de una matriz / lista para 40 elementos: https://.com/a/10762995/949129

Aquí está la clase de ayuda que uso para desinfectar caminos. Olvidé ahora por qué tenía la opción de reemplazo elegante, pero está ahí como una bonificación extra.

Método adicional de bonificación "IsValidLocalPath" también :)

(** los que no usan expresiones regulares)

public static class PathExtensions { private static HashSet<char> _invalidFilenameChars; private static HashSet<char> InvalidFilenameChars { get { return _invalidFilenameChars ?? (_invalidFilenameChars = new HashSet<char>(Path.GetInvalidFileNameChars())); } } /// <summary>Replaces characters in <c>text</c> that are not allowed in file names with the /// specified replacement character.</summary> /// <param name="text">Text to make into a valid filename. The same string is returned if /// it is valid already.</param> /// <param name="replacement">Replacement character, or NULL to remove bad characters.</param> /// <param name="fancyReplacements">TRUE to replace quotes and slashes with the non-ASCII characters ” and ⁄.</param> /// <returns>A string that can be used as a filename. If the output string would otherwise be empty, "_" is returned.</returns> public static string ToValidFilename(this string text, char? replacement = ''_'', bool fancyReplacements = false) { StringBuilder sb = new StringBuilder(text.Length); HashSet<char> invalids = InvalidFilenameChars; bool changed = false; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (invalids.Contains(c)) { changed = true; char repl = replacement ?? ''/0''; if (fancyReplacements) { if (c == ''"'') repl = ''”''; // U+201D right double quotation mark else if (c == ''/''') repl = ''’''; // U+2019 right single quotation mark else if (c == ''/'') repl = ''⁄''; // U+2044 fraction slash } if (repl != ''/0'') sb.Append(repl); } else sb.Append(c); } if (sb.Length == 0) return "_"; return changed ? sb.ToString() : text; } /// <summary> /// Returns TRUE if the specified path is a valid, local filesystem path. /// </summary> /// <param name="pathString"></param> /// <returns></returns> public static bool IsValidLocalPath(this string pathString) { // From solution at https://.com/a/11636052/949129 Uri pathUri; Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri); return isValidUri && pathUri != null && pathUri.IsLoopback; } }


Escribí este monstruo por diversión, te permite ida y vuelta:

public static class FileUtility { private const char PrefixChar = ''%''; private static readonly int MaxLength; private static readonly Dictionary<char,char[]> Illegals; static FileUtility() { List<char> illegal = new List<char> { PrefixChar }; illegal.AddRange(Path.GetInvalidFileNameChars()); MaxLength = illegal.Select(x => ((int)x).ToString().Length).Max(); Illegals = illegal.ToDictionary(x => x, x => ((int)x).ToString("D" + MaxLength).ToCharArray()); } public static string FilenameEncode(string s) { var builder = new StringBuilder(); char[] replacement; using (var reader = new StringReader(s)) { while (true) { int read = reader.Read(); if (read == -1) break; char c = (char)read; if(Illegals.TryGetValue(c,out replacement)) { builder.Append(PrefixChar); builder.Append(replacement); } else { builder.Append(c); } } } return builder.ToString(); } public static string FilenameDecode(string s) { var builder = new StringBuilder(); char[] buffer = new char[MaxLength]; using (var reader = new StringReader(s)) { while (true) { int read = reader.Read(); if (read == -1) break; char c = (char)read; if (c == PrefixChar) { reader.Read(buffer, 0, MaxLength); var encoded =(char) ParseCharArray(buffer); builder.Append(encoded); } else { builder.Append(c); } } } return builder.ToString(); } public static int ParseCharArray(char[] buffer) { int result = 0; foreach (char t in buffer) { int digit = t - ''0''; if ((digit < 0) || (digit > 9)) { throw new ArgumentException("Input string was not in the correct format"); } result *= 10; result += digit; } return result; } }


Esto parece ser O (n) y no gasta demasiada memoria en cadenas:

private static readonly HashSet<char> invalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars()); public static string RemoveInvalidFileNameChars(string name) { if (!name.Any(c => invalidFileNameChars.Contains(c))) { return name; } return new string(name.Where(c => !invalidFileNameChars.Contains(c)).ToArray()); }


Esto querrá que quieras, y evitarás colisiones.

static string SanitiseFilename(string key) { var invalidChars = Path.GetInvalidFileNameChars(); var sb = new StringBuilder(); foreach (var c in key) { var invalidCharIndex = -1; for (var i = 0; i < invalidChars.Length; i++) { if (c == invalidChars[i]) { invalidCharIndex = i; } } if (invalidCharIndex > -1) { sb.Append("_").Append(invalidCharIndex); continue; } if (c == ''_'') { sb.Append("__"); continue; } sb.Append(c); } return sb.ToString(); }


Intenta algo como esto en su lugar;

string illegal = "/"M/"//a/ry/ h**ad:>> a///:*?/"| li*tt|le|| la/"mb.?"; string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); foreach (char c in invalid) { illegal = illegal.Replace(c.ToString(), ""); }

Pero tengo que estar de acuerdo con los comentarios, probablemente trataría de lidiar con la fuente de las rutas ilegales, en lugar de intentar destruir una ruta ilegal en una legítima pero probablemente no intencionada.

Edición: O una solución potencialmente "mejor", utilizando Regex.

string illegal = "/"M/"//a/ry/ h**ad:>> a///:*?/"| li*tt|le|| la/"mb.?"; string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch))); illegal = r.Replace(illegal, "");

Aún así, la pregunta es por preguntarse por qué estás haciendo esto en primer lugar.


La mayoría de las soluciones anteriores combinan caracteres ilegales para la ruta y el nombre de archivo, lo que es incorrecto (incluso cuando ambas llamadas devuelven actualmente el mismo conjunto de caracteres). Primero dividiría la ruta + nombre de archivo en ruta y nombre de archivo, luego aplicaré el conjunto apropiado a cualquiera de ellos y luego combinaré los dos nuevamente.

wvd_vegt


La mejor manera de eliminar el carácter ilegal de la entrada del usuario es reemplazar el carácter ilegal utilizando la clase Regex, crear un método en el código detrás o también validarlo en el lado del cliente mediante el control RegularExpression.

public string RemoveSpecialCharacters(string str) { return Regex.Replace(str, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled); }

O

<asp:RegularExpressionValidator ID="regxFolderName" runat="server" ErrorMessage="Enter folder name with a-z A-Z0-9_" ControlToValidate="txtFolderName" Display="Dynamic" ValidationExpression="^[a-zA-Z0-9_]*$" ForeColor="Red">


Lanzar una excepción.

if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 ) { throw new ArgumentException(); }


O simplemente puedes hacer

[YOUR STRING].Replace(''//', '' '').Replace(''/'', '' '').Replace(''"'', '' '').Replace(''*'', '' '').Replace('':'', '' '').Replace(''?'', '' '').Replace(''<'', '' '').Replace(''>'', '' '').Replace(''|'', '' '').Trim();


Para empezar, Recortar solo elimina caracteres del principio o final de la cadena . En segundo lugar, debe evaluar si realmente desea eliminar los caracteres ofensivos, o fallar rápidamente y dejarle saber al usuario que su nombre de archivo no es válido. Mi elección es la última, pero mi respuesta al menos debería mostrarle cómo hacer las cosas de la manera correcta Y incorrecta:

Pregunta de que muestra cómo verificar si una cadena dada es un nombre de archivo válido . Tenga en cuenta que puede usar la expresión regular de esta pregunta para eliminar los caracteres con un reemplazo de expresión regular (si realmente necesita hacerlo).


Para nombres de archivos:

string cleanFileName = String.Join("", fileName.Split(Path.GetInvalidFileNameChars()));

Por caminos completos:

string cleanPath = String.Join("", path.Split(Path.GetInvalidPathChars()));


Prefiero absolutamente la idea de Jeff Yates. Funcionará perfectamente, si lo modificas ligeramente:

string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()))); Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

La mejora es solo para escapar de la expresión regular generada automáticamente.


Puedes eliminar caracteres ilegales usando Linq como este:

var invalidChars = Path.GetInvalidFileNameChars(); var invalidCharsRemoved = stringWithInvalidChars .Where(x => !invalidChars.Contains(x)) .ToArray();

EDITAR
Así es como se ve con la edición requerida mencionada en los comentarios:

var invalidChars = Path.GetInvalidFileNameChars(); string invalidCharsRemoved = new string(stringWithInvalidChars .Where(x => !invalidChars.Contains(x)) .ToArray());


Si elimina o reemplaza con un solo carácter los caracteres no válidos, puede tener colisiones:

<abc -> abc >abc -> abc

Aquí hay un método simple para evitar esto:

public static string ReplaceInvalidFileNameChars(string s) { char[] invalidFileNameChars = System.IO.Path.GetInvalidFileNameChars(); foreach (char c in invalidFileNameChars) s = s.Replace(c.ToString(), "[" + Array.IndexOf(invalidFileNameChars, c) + "]"); return s; }

El resultado:

<abc -> [1]abc >abc -> [2]abc


Todas estas son soluciones excelentes, pero todas dependen de Path.GetInvalidFileNameChars , que pueden no ser tan confiables como parece. Observe el siguiente comentario en la documentación de MSDN en Path.GetInvalidFileNameChars :

No se garantiza que la matriz devuelta por este método contenga el conjunto completo de caracteres que no son válidos en los nombres de archivos y directorios. El conjunto completo de caracteres no válidos puede variar según el sistema de archivos. Por ejemplo, en plataformas de escritorio basadas en Windows, los caracteres de ruta no válidos pueden incluir los caracteres ASCII / Unicode 1 a 31, así como comillas ("), menores que (<), mayores que (>), canalizaciones (|), retroceso ( / b), nulo (/ 0) y tabulador (/ t).

No es mejor con el método Path.GetInvalidPathChars . Contiene exactamente el mismo comentario.


Uso expresiones regulares para lograr esto. Primero, construyo dinámicamente el regex.

string regex = string.Format( "[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()))); Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

Luego llamo removeInvalidChars.Replace para buscar y reemplazar. Obviamente, esto también puede extenderse para cubrir los caracteres del camino.


Yo uso Linq para limpiar los nombres de archivos. También puede extenderlo fácilmente para comprobar si hay rutas válidas.

private static string CleanFileName(string fileName) { return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty)); }

Actualizar

Algunos comentarios indican que este método no funciona para ellos, por lo que he incluido un enlace a un fragmento de código DotNetFiddle para que pueda validar el método.

https://dotnetfiddle.net/nw1SWY


public static bool IsValidFilename(string testName) { return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName); }


public static class StringExtensions { public static string RemoveUnnecessary(this string source) { string result = string.Empty; string regex = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); Regex reg = new Regex(string.Format("[{0}]", Regex.Escape(regex))); result = reg.Replace(source, ""); return result; } }

Puedes usar el método claramente.


public string GetSafeFilename(string filename) { return string.Join("_", filename.Split(Path.GetInvalidFileNameChars())); }

Esta respuesta estaba en otro hilo de Ceres , realmente me gusta limpio y simple.