12 ответов:
тьфу, я ненавижу, когда люди пытаются угадать, какие символы допустимы. Помимо того, что он полностью непортативен (всегда думая о моно), оба предыдущих комментария пропустили более 25 недопустимых символов.
'Clean just a filename Dim filename As String = "salmnas dlajhdla kjha;dmas'lkasn" For Each c In IO.Path.GetInvalidFileNameChars filename = filename.Replace(c, "") Next 'See also IO.Path.GetInvalidPathChars
этот вопрос был задан многовременидо и, как указывалось много раз ранее,
IO.Path.GetInvalidFileNameCharsне адекватен.во-первых, есть много имен, таких как PRN и CON, которые зарезервированы и не разрешены для имен файлов. Есть и другие имена, не разрешенные только в корневой папке. Имена, заканчивающиеся на точку, также не допускаются.
во-вторых, существует множество ограничений длины. Прочитайте полный список для NTFS здесь.
в-третьих, вы можете подключаться к файловым системам, которые имеют другие ограничения. Например, имена файлов ISO 9660 не могут начинаться с" -", но могут содержать его.
В-четвертых, что вы делаете, если два процесса "произвольно" выбирают одно и то же имя?
В общем, использование внешних имен для имен файлов-плохая идея. Я предлагаю создавать свои собственные имена частных файлов и хранить имена, читаемые человеком внутри.
чтобы удалить недопустимые символы:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); // Builds a string out of valid chars var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());для замены недопустимых символов:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); // Builds a string out of valid chars and an _ for invalid ones var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? '_' : ch).ToArray());чтобы заменить недопустимые символы (и избежать потенциального конфликта имен, такого как Hell * vs Hell$):
static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars(); // Builds a string out of valid chars and replaces invalid chars with a unique letter (Moves the Char into the letter range of unicode, starting at "A") var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
Я согласен с Grauenwolf и очень рекомендую
Path.GetInvalidFileNameChars()вот мой вклад в C#:
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))"; Array.ForEach(Path.GetInvalidFileNameChars(), c => file = file.Replace(c.ToString(), String.Empty));p. s. -- это более загадочно, чем должно быть -- я пытался быть кратким.
вот мой вариант:
static string GetSafeFileName(string name, char replace = '_') { char[] invalids = Path.GetInvalidFileNameChars(); return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray()); }Я не уверен, как вычисляется результат GetInvalidFileNameChars, но" Get " предполагает, что это нетривиально, поэтому я кэширую результаты. Кроме того, это только пересекает входную строку один раз, а не несколько раз, как решения выше, которые повторяют набор недопустимых символов, заменяя их в исходной строке по одному за раз. Кроме того, мне нравятся решения на основе Where, но я предпочитаю заменять недопустимые символы вместо их удаления. Наконец, моя замена-это ровно один символ, чтобы избежать преобразования символов в строки, когда я повторяю строку.
Я говорю все, что без профилирования-это просто "чувствовал" хорошо для меня. :)
вот функция, которую я использую сейчас (спасибо jcollum за пример C#):
public static string MakeSafeFilename(string filename, char replaceChar) { foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { filename = filename.Replace(c, replaceChar); } return filename; }Я просто положил это в класс "помощники" для удобства.
Если вы хотите быстро удалить все специальные символы, которые иногда более удобочитаемы для имен файлов, это хорошо работает:
string myCrazyName = "q`w^e!r@t#y$u%i^o&p*a(s)d_f-g+h=j{k}l|z:x\"c<v>b?n[m]q\w;e'r,t.y/u"; string safeName = Regex.Replace( myCrazyName, "\W", /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/ "", RegexOptions.IgnoreCase); // safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"
static class Utils { public static string MakeFileSystemSafe(this string s) { return new string(s.Where(IsFileSystemSafe).ToArray()); } public static bool IsFileSystemSafe(char c) { return !Path.GetInvalidFileNameChars().Contains(c); } }
вот что я только что добавил в ClipFlair (http://clipflair.codeplex.com) статический класс StringExtensions (Utils.Silverlight project), на основе информации, собранной из ссылок на связанные вопросы stackoverflow, опубликованные Dour High Arch выше:
public static string ReplaceInvalidFileNameChars(this string s, string replacement = "") { return Regex.Replace(s, "[" + Regex.Escape(new String(System.IO.Path.GetInvalidPathChars())) + "]", replacement, //can even use a replacement string of any length RegexOptions.IgnoreCase); //not using System.IO.Path.InvalidPathChars (deprecated insecure API) }
почему бы не преобразовать строку в эквивалент Base64 следующим образом:
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn"; string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));Если вы хотите, чтобы преобразовать его обратно так что вы можете прочитать это:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));я использовал это, чтобы сохранить PNG файлы с уникальным именем из случайного описания.
private void textBoxFileName_KeyPress(object sender, KeyPressEventArgs e) { e.Handled = CheckFileNameSafeCharacters(e); } /// <summary> /// This is a good function for making sure that a user who is naming a file uses proper characters /// </summary> /// <param name="e"></param> /// <returns></returns> internal static bool CheckFileNameSafeCharacters(System.Windows.Forms.KeyPressEventArgs e) { if (e.KeyChar.Equals(24) || e.KeyChar.Equals(3) || e.KeyChar.Equals(22) || e.KeyChar.Equals(26) || e.KeyChar.Equals(25))//Control-X, C, V, Z and Y return false; if (e.KeyChar.Equals('\b'))//backspace return false; char[] charArray = Path.GetInvalidFileNameChars(); if (charArray.Contains(e.KeyChar)) return true;//Stop the character from being entered into the control since it is non-numerical else return false; }
Я считаю, что с помощью этого, чтобы быть быстрым и легким для понимания:
<Extension()> Public Function MakeSafeFileName(FileName As String) As String Return FileName.Where(Function(x) Not IO.Path.GetInvalidFileNameChars.Contains(x)).ToArray End Functionэто работает, потому что a
stringиIEnumerableкакcharмассив и естьstringстрока конструктора, которая принимаетcharмассив.
Comments