2008-12-02 22 views
71

我的程序将从互联网上取任意字符串并将它们用于文件名。有没有简单的方法来从这些字符串中删除坏字符,还是需要为此编写一个自定义函数?有没有在c#中使字符串文件路径安全的方法?

+0

可能的重复[安全/允许的文件名清理器的.NET](http://stackoverflow.com/questions/1862993/safe-allowed-filename-cleaner-for-net) – N8allan 2015-07-02 22:51:38

回答

148

呃,我讨厌它,当人们试图猜测哪些字符是有效的。除了完全不可移植(总是考虑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 
+0

这可能不会有太大的区别这个情况。 Windows错误只会抱怨少数人物。感谢您指出GetInvalidFileNameChars,但我之前没有遇到过。我会记住它。 – BenAlabaster 2008-12-02 08:29:56

+65

C#版本:foreach(Path.GetInvalidFileNameChars()中的var c){fileName = fileName.Replace(c,' - '); } – jcollum 2010-02-15 22:12:21

+8

该解决方案如何处理名称冲突?看起来,多个字符串可以匹配单个文件名(例如“Hell?”和“Hell *”)。如果你没事的话只能删除冒犯的字符然后罚款;否则你需要小心处理名称冲突。 – 2011-06-13 09:55:21

19

我同意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)); 

附: - 这比应该更神秘 - 我试图简洁。

6

如果你想快速去掉所有特殊字符,有时多个用户可读的文件名这个工作得很好:

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" 
10

下面是我现在使用(对于C#示例感谢jcollum)功能:

public static string MakeSafeFilename(string filename, char replaceChar) 
{ 
    foreach (char c in System.IO.Path.GetInvalidFileNameChars()) 
    { 
     filename = filename.Replace(c, replaceChar); 
    } 
    return filename; 
} 

为了方便,我只是把它放在“助手”类中。

20

要去除无效字符:

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()); 

要更换无效字符(并避免潜在的名称冲突像地狱* VS地狱$):

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()); 
29

此问题被询问manytimesbefore,正如前面多次指出的那样,IO.Path.GetInvalidFileNameChars是不够的。

首先,像PRN和CON这样的许多名字是保留的,不允许用于文件名。还有其他名称不允许在根文件夹中。在一段时间内结束的名称也是不允许的。

其次,有各种长度限制。请阅读NTFS here的完整列表。

第三,您可以附加到具有其他限制的文件系统。例如,ISO 9660文件名不能以“ - ”开头,但可以包含它。

四,如果两个进程“随意”选择同一个名字,你会怎么做?

通常,将外部生成的名称用于文件名是一个坏主意。我建议生成自己的私人文件名并在内部存储人类可读的名称。

1

我发现使用这是快速和容易理解:

<Extension()> 
Public Function MakeSafeFileName(FileName As String) As String 
    Return FileName.Where(Function(x) Not IO.Path.GetInvalidFileNameChars.Contains(x)).ToArray 
End Function 

这工作,因为一个stringIEnumerable作为char阵列,有一个string构造函数的字符串,需要char阵列。

4
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); 
    } 
} 
4

这里就是我刚刚加入到ClipFlair的(http://clipflair.codeplex.com)StringExtensions静态类(Utils.Silverlight项目)的基础上,从发布的杜尔高拱坝上面的链接到相关的计算器问题收集信息:

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) 
} 
11

这里是我的版本:

static string GetSafeFileName(string name, char replace = '_') { 
    char[] invalids = Path.GetInvalidFileNameChars(); 
    return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray()); 
} 

我不知道如何GetInvalidFileNameChars的结果进行计算,但“获取”表明,它是无小事l,所以我缓存结果。此外,这只会遍历输入字符串一次而不是多次,就像上面的解决方案遍历一组无效字符,一次替换一个源字符串中的字符串。另外,我喜欢基于位置的解决方案,但我更喜欢替换无效的字符而不是删除它们。最后,我的替换正好是一个字符,以避免在字符串迭代时将字符转换为字符串。

我说所有没有做分析的人 - 这个只是“感觉”对我很好。 :)

2
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;    
} 
2

为什么不将字符串转换到Base64相当于是这样的:如果你想将其转换回

string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn"; 
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName)); 

,所以你可以阅读:

UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName)); 

我用这从随机描述中保存具有唯一名称的PNG文件。

相关问题