Есть ли способ сделать строки с файловым безопасным в С#?
Моя программа будет брать произвольные строки из Интернета и использовать их для имен файлов. Есть ли простой способ удалить плохие символы из этих строк или мне нужно написать для этого специальную функцию?
Ответы
Ответ 1
Ух, я ненавижу, когда люди пытаются угадать, какие символы действительны. Помимо того, что он полностью не переносится (всегда думая о Mono), оба предыдущих комментария пропустили более 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
Ответ 2
Этот вопрос задавался много раз ранее, и, как уже много раз указывалось ранее, IO.Path.GetInvalidFileNameChars
не подходит.
Во-первых, есть много имен, таких как PRN и CON, которые зарезервированы и недопустимы для имен файлов. Другие имена не разрешены только в корневой папке. Имена, заканчивающиеся точкой, также не допускаются.
Во-вторых, существуют различные ограничения по длине. Читайте полный список для NTFS здесь.
В-третьих, вы можете подключиться к файловым системам, которые имеют другие ограничения. Например, имена файлов ISO 9660 не могут начинаться с "-", но могут содержать их.
В-четвертых, что вы делаете, если два процесса "произвольно" выбирают одно и то же имя?
В общем, использование сгенерированных извне имен для имен файлов - плохая идея. Я предлагаю генерировать ваши собственные личные имена файлов и хранить удобочитаемые имена для внутреннего использования.
Ответ 3
Чтобы удалить недопустимые символы:
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());
Ответ 4
Я согласен с Grauenwolf и очень рекомендую Path.GetInvalidFileNameChars()
Здесь мой вклад С#:
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
c => file = file.Replace(c.ToString(), String.Empty));
p.s. - Это более загадочно, чем должно быть - я старался быть кратким.
Ответ 5
Здесь моя версия:
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-based, но я предпочитаю заменять неверные символы вместо их удаления. Наконец, моя замена - это ровно один символ, чтобы избежать преобразования символов в строки, когда я перебираю строку.
Я говорю все, что не делаю профилирования - этот просто "чувствовал" приятный для меня.:)
Ответ 6
Здесь функция, которую я использую сейчас (спасибо jcollum для примера С#):
public static string MakeSafeFilename(string filename, char replaceChar)
{
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
filename = filename.Replace(c, replaceChar);
}
return filename;
}
Я просто поместил это в класс "Помощники" для удобства.
Ответ 7
Если вы хотите быстро удалить все специальные символы, которые иногда более читабельны для имен файлов, это прекрасно работает:
string myCrazyName = "q`w^[email protected]#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"
Ответ 8
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);
}
}
Ответ 9
Вот что я только что добавил в ClipFlair (http://github.com/Zoomicon/ClipFlair) статический класс StringExtensions (проект Utils.Silverlight), основанный на информации, собранной из ссылок на связанные вопросы по 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)
}
Ответ 10
Почему бы не преобразовать строку в эквивалент Base64 следующим образом:
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn";
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
Если вы хотите преобразовать его, чтобы вы могли его прочитать:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
Я использовал это, чтобы сохранить PNG файлы с уникальным именем из случайного описания.
Ответ 11
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;
}
Ответ 12
Я считаю, что использовать это быстро и легко понять:
<Extension()>
Public Function MakeSafeFileName(FileName As String) As String
Return FileName.Where(Function(x) Not IO.Path.GetInvalidFileNameChars.Contains(x)).ToArray
End Function
Это работает, потому что string
является IEnumerable
как массив char
, и есть строка конструктора string
, которая принимает массив char
.
Ответ 13
Многие из них предлагают использовать Path.GetInvalidFileNameChars()
что мне кажется плохим решением. Я рекомендую вам использовать белый список вместо черного, потому что хакеры всегда найдут способ обойти его.
Вот пример кода, который вы можете использовать:
string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
foreach (char c in filename)
{
if (!whitelist.Contains(c))
{
filename = filename.Replace(c, '-');
}
}