有没有办法使string文件path在C#安全?
我的程序将从互联网上采取任意string,并将其用于文件名。 有一个简单的方法来从这些string中删除错误的字符,或者我需要为此编写一个自定义函数吗?
呃,当人们试图猜测哪些字符是有效的,我讨厌它。 除了完全不可移植(总是考虑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
这个问题之前已经被问过很多 次了 ,正如前面多次指出的那样, IO.Path.GetInvalidFileNameChars
是不够的。
首先,像PRN和CON这样的许多名称是保留的,不允许使用文件名。 还有其他的名字只允许在根文件夹中。 在一段时间内结束的名字也是不允许的。
其次,有各种长度限制。 在这里阅读NTFS的完整列表。
第三,你可以附加到有其他限制的文件系统。 例如,ISO 9660文件名不能以“ – ”开头,但可以包含它。
第四,如果两个程序“随意”select同一个名字,你会做什么?
通常,将外部生成的名称用于文件名是一个坏主意。 我build议生成你自己的私人文件名并在内部存储人类可读的名字。
去除无效字符:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); // Builds a string out of valid chars var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());
要replace无效字符:
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());
要replace无效字符(并避免可能的名称冲突像地狱* vs地狱$):
static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars(); // Builds a string out of valid chars and replaces invalid chars with a unique letter var validFilename = new string(filename.Select(ch => InvalidFileNameChars.Contains(ch) ? Convert.ToChar(InvalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
我同意Grauenwolf,并强烈build议Path.GetInvalidFileNameChars()
这是我的C#贡献:
string file = @"38?/.\}[+=n a882 aa*/|n^%$ ad#(-))"; Array.ForEach(Path.GetInvalidFileNameChars(), c => file = file.Replace(c.ToString(), String.Empty));
ps – 这比应该更神秘 – 我试图简洁。
这里是我现在使用的function(感谢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; }
为了方便,我只是把它放在“助手”类中。
这是我的版本:
static string GetSafeFileName(string name, char replace = '_') { char[] invalids = Path.GetInvalidFileNameChars(); return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray()); }
我不知道如何计算GetInvalidFileNameChars的结果,但“获取”表明它是不平凡的,所以我caching结果。 此外,这只会遍历一次inputstring而不是多次,就像上面迭代遍历一组无效字符的解决scheme,一次replace一个源string中的string。 另外,我喜欢基于位置的解决scheme,但我更喜欢replace无效的字符而不是删除它们。 最后,我的replace正好是一个字符,以避免将字符转换为string,因为我遍历string。
我说所有没有做分析的人 – 这个只是“感觉”对我很好。 :)
如果你想快速删除所有特殊字符,有时更多的用户可读的文件名,这很好地工作:
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,ty/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项目),基于从上面Dour High Arch发布的相关的stackoverflow问题的链接收集的信息:
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) }
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
这是因为一个string
是IEnumerable
作为一个char
数组,并且有一个string
构造函数string需要一个char
数组。
为什么不把string转换成像这样的Base64等价物:
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn"; string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
如果你想把它转换回来,所以你可以阅读它:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
我用这个从随机描述保存具有唯一名称的PNG文件。