2008-12-02 60 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文件。

相關問題