我最近一直在将各种位置的MP3转移到存储库中.我一直使用ID3标签构建新的文件名(谢谢,TagLib-Sharp!),我注意到我得到了一个System.NotSupportedException
:
"不支持给定路径的格式."
这是通过产生任一File.Copy()
或Directory.CreateDirectory()
.
没过多久就意识到我的文件名需要消毒.所以我做了一件显而易见的事:
public static string SanitizePath_(string path, char replaceChar) { string dir = Path.GetDirectoryName(path); foreach (char c in Path.GetInvalidPathChars()) dir = dir.Replace(c, replaceChar); string name = Path.GetFileName(path); foreach (char c in Path.GetInvalidFileNameChars()) name = name.Replace(c, replaceChar); return dir + name; }
令我惊讶的是,我继续得到例外.原来,':'不在集合中Path.GetInvalidPathChars()
,因为它在路径根中有效.我认为这是有道理的 - 但这必须是一个非常普遍的问题.有没有人有一些消毒路径的短代码?最彻底的我已经想到了这一点,但感觉它可能是矫枉过正.
// replaces invalid characters with replaceChar public static string SanitizePath(string path, char replaceChar) { // construct a list of characters that can't show up in filenames. // need to do this because ":" is not in InvalidPathChars if (_BadChars == null) { _BadChars = new List(Path.GetInvalidFileNameChars()); _BadChars.AddRange(Path.GetInvalidPathChars()); _BadChars = Utility.GetUnique (_BadChars); } // remove root string root = Path.GetPathRoot(path); path = path.Remove(0, root.Length); // split on the directory separator character. Need to do this // because the separator is not valid in a filename. List parts = new List (path.Split(new char[]{Path.DirectorySeparatorChar})); // check each part to make sure it is valid. for (int i = 0; i < parts.Count; i++) { string part = parts[i]; foreach (char c in _BadChars) { part = part.Replace(c, replaceChar); } parts[i] = part; } return root + Utility.Join(parts, Path.DirectorySeparatorChar.ToString()); }
任何改进使这个功能更快,更少巴洛克非常值得赞赏.
要清理文件名,您可以执行此操作
private static string MakeValidFileName( string name ) { string invalidChars = System.Text.RegularExpressions.Regex.Escape( new string( System.IO.Path.GetInvalidFileNameChars() ) ); string invalidRegStr = string.Format( @"([{0}]*\.+$)|([{0}]+)", invalidChars ); return System.Text.RegularExpressions.Regex.Replace( name, invalidRegStr, "_" ); }
更短的解决方案:
var invalids = System.IO.Path.GetInvalidFileNameChars(); var newName = String.Join("_", origFileName.Split(invalids, StringSplitOptions.RemoveEmptyEntries) ).TrimEnd('.');
基于安德烈的出色答案,但考虑到斯普德对保留字的评论,我制作了这个版本:
////// Strip illegal chars and reserved words from a candidate filename (should not include the directory path) /// ////// http://stackoverflow.com/questions/309485/c-sharp-sanitize-file-name /// public static string CoerceValidFileName(string filename) { var invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars())); var invalidReStr = string.Format(@"[{0}]+", invalidChars); var reservedWords = new [] { "CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; var sanitisedNamePart = Regex.Replace(filename, invalidReStr, "_"); foreach (var reservedWord in reservedWords) { var reservedWordPattern = string.Format("^{0}\\.", reservedWord); sanitisedNamePart = Regex.Replace(sanitisedNamePart, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase); } return sanitisedNamePart; }
这些是我的单元测试
[Test] public void CoerceValidFileName_SimpleValid() { var filename = @"thisIsValid.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual(filename, result); } [Test] public void CoerceValidFileName_SimpleInvalid() { var filename = @"thisIsNotValid\3\\_3.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("thisIsNotValid_3__3.txt", result); } [Test] public void CoerceValidFileName_InvalidExtension() { var filename = @"thisIsNotValid.t\xt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("thisIsNotValid.t_xt", result); } [Test] public void CoerceValidFileName_KeywordInvalid() { var filename = "aUx.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("_reservedWord_.txt", result); } [Test] public void CoerceValidFileName_KeywordValid() { var filename = "auxillary.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("auxillary.txt", result); }
string clean = String.Concat(dirty.Split(Path.GetInvalidFileNameChars()));