我有一个像"Foo:Bar"这样的字符串我想用作文件名,但在Windows上,文件名中不允许使用":"字符.
有没有一种方法可以将"Foo:Bar"变成像"Foo-Bar"这样的东西?
尝试这样的事情:
string fileName = "something"; foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { fileName = fileName.Replace(c, '_'); }
编辑:
由于GetInvalidFileNameChars()
将返回10或15个字符,最好使用StringBuilder
而不是简单的字符串; 原始版本将花费更长时间并消耗更多内存.
fileName = fileName.Replace(":", "-")
但是":"并不是Windows的唯一非法字符.你还必须处理:
/, \, :, *, ?, ", <, > and |
这些包含在System.IO.Path.GetInvalidFileNameChars();
另外(在Windows上),"." 不能是文件名中唯一的字符(".","..","..."等都无效).使用"."命名文件时要小心,例如:
echo "test" > .test.
将生成一个名为".test"的文件
最后,如果你真的想要正确地做事,你需要注意一些特殊的文件名.在Windows上,您无法创建名为的文件:
CON, PRN, AUX, CLOCK$, NUL COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9 LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.
这不是更有效,但它更有趣:)
var fileName = "foo:bar"; var invalidChars = System.IO.Path.GetInvalidFileNameChars(); var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray());
如果有人想要基于的优化版本StringBuilder
,请使用此功能.包括rkagerer的诀窍作为选项.
static char[] _invalids; ///Replaces characters in /// Text to make into a valid filename. The same string is returned if it is valid already. /// Replacement character, or null to simply remove bad characters. /// Whether to replace quotes and slashes with the non-ASCII characters ” and ?. ///text that are not allowed in /// file names with the specified replacement character.A string that can be used as a filename. If the output string would otherwise be empty, returns "_". public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true) { StringBuilder sb = new StringBuilder(text.Length); var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars()); bool changed = false; for (int i = 0; i < text.Length; i++) { char c = text[i]; if (invalids.Contains(c)) { changed = true; var repl = replacement ?? '\0'; if (fancy) { 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; }
迭戈确实有正确的解决方案,但那里有一个非常小的错误.使用的string.Replace的版本应该是string.Replace(char,char),没有string.Replace(char,string)
我无法编辑答案,或者我只是做了一些小改动.
所以它应该是:
string fileName = "something"; foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { fileName = fileName.Replace(c, '_'); }
迭戈的回答略有不同.
如果你不害怕Unicode,你可以通过用类似它们的有效Unicode符号替换无效字符来保持更高的保真度.这是我最近涉及木材切割清单的项目中使用的代码:
static string MakeValidFilename(string text) { text = text.Replace('\'', '’'); // U+2019 right single quotation mark text = text.Replace('"', '”'); // U+201D right double quotation mark text = text.Replace('/', '?'); // U+2044 fraction slash foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { text = text.Replace(c, '_'); } return text; }
这会产生类似的文件名1?2” spruce.txt
而不是1_2_ spruce.txt
是的,它确实有效:
买者自负
我知道这个技巧可以在NTFS上运行,但很惊讶它发现它也适用于FAT和FAT32分区.这是因为长文件名都以Unicode格式存储,甚至可以追溯到与Windows 95/NT.我在Win7,XP甚至基于Linux的路由器上进行了测试,他们出现了.对于DOSBox内部不能说相同.
也就是说,在你坚持下去之前,先考虑一下你是否真的需要额外的保真度.Unicode外观可能会混淆人们或旧程序,例如旧操作系统依赖于代码页.
下面是使用公认的答案的一个版本,Linq
它的用途Enumerable.Aggregate
:
string fileName = "something"; Path.GetInvalidFileNameChars() .Aggregate(fileName, (current, c) => current.Replace(c, '_'));
这是使用StringBuilder
并IndexOfAny
带有批量附加以提高效率的版本。它还返回原始字符串,而不是创建重复的字符串。
最后但并非最不重要的一点是,它具有switch语句,该语句返回外观相似的字符,您可以根据需要自定义任何方式。查看Unicode.org的易混淆查询,以查看可能有哪些选项,具体取决于字体。
public static string GetSafeFilename(string arbitraryString) { var invalidChars = System.IO.Path.GetInvalidFileNameChars(); var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0); if (replaceIndex == -1) return arbitraryString; var r = new StringBuilder(); var i = 0; do { r.Append(arbitraryString, i, replaceIndex - i); switch (arbitraryString[replaceIndex]) { case '"': r.Append("''"); break; case '<': r.Append('\u02c2'); // '?' (modifier letter left arrowhead) break; case '>': r.Append('\u02c3'); // '?' (modifier letter right arrowhead) break; case '|': r.Append('\u2223'); // '?' (divides) break; case ':': r.Append('-'); break; case '*': r.Append('\u2217'); // '?' (asterisk operator) break; case '\\': case '/': r.Append('\u2044'); // '?' (fraction slash) break; case '\0': case '\f': case '?': break; case '\t': case '\n': case '\r': case '\v': r.Append(' '); break; default: r.Append('_'); break; } i = replaceIndex + 1; replaceIndex = arbitraryString.IndexOfAny(invalidChars, i); } while (replaceIndex != -1); r.Append(arbitraryString, i, arbitraryString.Length - i); return r.ToString(); }
它不检查.
,..
或像保留名称CON
,因为它没有明确的更换应该是什么。