क्या स्ट्रिंग फ़ाइल-पथ बनाने का एक तरीका c # में सुरक्षित है?


92

मेरा कार्यक्रम इंटरनेट से मनमाना तार लेगा और उन्हें फ़ाइल नामों के लिए उपयोग करेगा। क्या इन तारों से बुरे पात्रों को हटाने का एक सरल तरीका है या क्या मुझे इसके लिए एक कस्टम फ़ंक्शन लिखने की आवश्यकता है?


जवाबों:


171

ऊ, मुझे इससे नफरत है जब लोग यह अनुमान लगाने की कोशिश करते हैं कि कौन से पात्र वैध हैं। पूरी तरह से गैर-पोर्टेबल होने (हमेशा मोनो के बारे में सोचने) के अलावा, पहले की दोनों टिप्पणियों में 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

83
C # संस्करण: foreach (Path c.GetInvalidFileNameChars () में) {fileName = fileName.Replace (c, '-'); }
jcollum

8
यह समाधान नाम विरोध को कैसे हैंडल करेगा? ऐसा लगता है कि एक से अधिक स्ट्रिंग एक एकल फ़ाइल नाम ("नर्क?" और "नर्क *" उदाहरण के लिए मेल कर सकते हैं)। यदि आप ठीक हैं केवल आपत्तिजनक चार्ट हटा रहे हैं तो ठीक; अन्यथा आपको नाम संघर्ष को संभालने के लिए सावधान रहने की आवश्यकता है।
स्टेफानो रिकियार्डी

2
नाम (और पथ) लंबाई की फाइलमाइट की सीमाओं के बारे में क्या? आरक्षित फ़ाइल नाम (PRN CON) के बारे में क्या? यदि आपको डेटा और मूल नाम को संग्रहीत करने की आवश्यकता है, तो आप मार्गदर्शक नामों के साथ 2 फ़ाइलों का उपयोग कर सकते हैं: guide.txt और guide.dat
जैक

6
एक लाइनर, मजेदार परिणाम के लिए = Path.GetInvalidFileNameChars ()। एग्रीगेट (परिणाम, (वर्तमान, c) => current.Replace (c, '-'));
पॉल नोपफ

1
@PaKKnopf, क्या आपको यकीन है कि JetBrain के पास उस कोड का कॉपीराइट नहीं है?)
Marcus

36

अमान्य वर्णों को हटाने के लिए:

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

अमान्य वर्णों को बदलने के लिए (और संभावित नाम संघर्ष जैसे नर्क * बनाम नर्क $) से बचें:

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

33

यह सवाल किया गया है पूछा कई बार पहले और, के रूप में कई बार कहा से पहले, IO.Path.GetInvalidFileNameCharsपर्याप्त नहीं है।

सबसे पहले, PRN और CON जैसे कई नाम हैं जो आरक्षित हैं और फ़ाइल नाम के लिए अनुमत नहीं हैं। केवल रूट फ़ोल्डर में अन्य नाम नहीं हैं। एक अवधि में समाप्त होने वाले नामों को भी अनुमति नहीं है।

दूसरा, लंबाई की सीमाएं हैं। NTFS के लिए पूरी सूची यहां पढ़ें ।

तीसरा, आप उन फाइल सिस्टम से जुड़ सकते हैं जिनकी अन्य सीमाएँ हैं। उदाहरण के लिए, आईएसओ 9660 फाइलनाम "-" के साथ शुरू नहीं हो सकता है, लेकिन इसमें हो सकता है।

चौथा, यदि आप दो प्रक्रियाएं "मनमाने ढंग से" एक ही नाम से करते हैं, तो आप क्या करते हैं?

सामान्य तौर पर, फ़ाइल नामों के लिए बाहरी रूप से जनरेट किए गए नामों का उपयोग करना एक बुरा विचार है। मेरा सुझाव है कि अपने निजी फ़ाइल नाम पैदा करें और आंतरिक रूप से मानव-पठनीय नामों को संग्रहीत करें।


13
हालाँकि आप तकनीकी रूप से सटीक हैं, फिर भी GetInvalidFileNameChars उन स्थितियों का 80% + के लिए अच्छा है जो आप इसमें उपयोग करेंगे, इसलिए यह एक अच्छा उत्तर है। मुझे लगता है कि स्वीकृत उत्तर के लिए एक टिप्पणी के रूप में आपका उत्तर अधिक उपयुक्त होगा।
क्यूबा 24

4
मैं DourHighArch से सहमत हूं। एक गाइड के रूप में फ़ाइल को आंतरिक रूप से सहेजें, संदर्भ दें कि "अनुकूल नाम" के खिलाफ जो एक डेटाबेस में संग्रहीत है। उपयोगकर्ताओं को वेबसाइट पर अपने पथ को नियंत्रित न करने दें या वे आपके web.config को चुराने की कोशिश करेंगे। यदि आप इसे साफ करने के लिए url पुनर्लेखन को शामिल करते हैं, तो यह केवल डेटाबेस में मिलान किए गए दोस्ताना यूआरएल के लिए काम करेगा।
rtpHarry

22

मैं ग्रेउनवुल्फ़ से सहमत हूँ और अत्यधिक सिफारिश करूँगा Path.GetInvalidFileNameChars()

यहाँ मेरा C # योगदान है:

string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(), 
      c => file = file.Replace(c.ToString(), String.Empty));

ps - यह जितना होना चाहिए, उससे अधिक गूढ़ है - मैं संक्षिप्त होने की कोशिश कर रहा था।


3
दुनिया में आप Array.ForEachसिर्फ foreachयहाँ के बजाय उपयोग क्यों करेंगे
ब्लूराजा - डैनी पफ्लुगुफ्ट

9
यदि आप अधिक संक्षिप्त / गूढ़ होना चाहते हैं:Path.GetInvalidFileNameChars().Aggregate(file, (current, c) => current.Replace(c, '-'))
माइकल पेटिटो

@ BlueRaja-DannyPflughoeft क्योंकि आप इसे धीमा बनाना चाहते हैं?
जोनाथन एलन

@ जोनाथन एलन, आपको क्या लगता है कि फॉर्च्यूनर Array.ForEach से अधिक तेज़ है?
बजे रयान बुदिकॉम

5
@rbuddicom Array.ForEach एक प्रतिनिधि लेता है, जिसका अर्थ है कि यह एक फ़ंक्शन को इनवॉइस करने की आवश्यकता नहीं है। छोटे तार के लिए, आप वास्तविक तर्क की तुलना में फ़ंक्शन कॉल ओवरहेड पर अधिक समय व्यतीत कर सकते हैं। .NET कोर "डी वर्चुअलाइज़" कॉल के तरीकों को देख रहा है, ओवरहेड को कम कर रहा है।
जोनाथन एलन

13

यहाँ मेरा संस्करण है:

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

मुझे यकीन नहीं है कि GetInvalidFileNameChars के परिणाम की गणना कैसे की जाती है, लेकिन "गेट" से पता चलता है कि यह गैर-तुच्छ है, इसलिए मैं परिणामों को कैश करता हूं। इसके अलावा, यह केवल इनपुट स्ट्रिंग को कई बार के बजाय एक बार बदल देता है, जैसे कि ऊपर दिए गए समाधान, जो अमान्य वर्णों के सेट पर पुनरावृति करते हैं, उन्हें एक समय में स्रोत स्ट्रिंग एक में प्रतिस्थापित करते हैं। इसके अलावा, मुझे कहाँ-आधारित समाधान पसंद हैं, लेकिन मैं उन्हें हटाने के बजाय अमान्य वर्णों को बदलना पसंद करता हूं। अंत में, मेरा प्रतिस्थापन एक चरित्र है जिसे स्ट्रिंग में परिवर्तित करने से पात्रों को परिवर्तित करने से बचने के लिए एक चरित्र है।

मैं कहता हूं कि सभी w / o प्रोफाइलिंग कर रहे हैं - यह एक "मुझे" अच्छा लगा। :)


1
आप new HashSet<char>(Path.GetInvalidFileNameChars())हे (एन) गणना - सूक्ष्म अनुकूलन से बचने के लिए कर सकते हैं ।
ट्रूविल

12

यहां वह फ़ंक्शन है जो मैं अभी उपयोग कर रहा हूं (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;
}

मैंने इसे सुविधा के लिए "हेल्पर्स" क्लास में रखा।


7

यदि आप सभी विशेष वर्णों को जल्दी से निकालना चाहते हैं, जो कभी-कभी फ़ाइल नामों के लिए अधिक उपयोगकर्ता पठनीय होता है, तो यह अच्छी तरह से काम करता है:

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,t.y/u";
string safeName = Regex.Replace(
    myCrazyName,
    "\W",  /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/
    "",
    RegexOptions.IgnoreCase);
// safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"

1
वास्तव में \Wगैर-अल्फा-न्यूमेरिक्स ( [^A-Za-z0-9_]) से अधिक मेल खाता है । सभी यूनिकोड के शब्द 'अक्षर' (русский etc. ..., आदि) को भी प्रतिस्थापित नहीं किया जाएगा। लेकिन यह अच्छी बात है।
इस्माइल

केवल नकारात्मक पक्ष यह है कि यह भी हटा देता है .इसलिए आपको पहले एक्सटेंशन को निकालना होगा, और उसके बाद फिर से जोड़ना होगा।
विस्मयकारी

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

5

इस तरह स्ट्रिंग को बेस 64 के बराबर क्यों न करें:

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

यदि आप इसे वापस बदलना चाहते हैं तो आप इसे पढ़ सकते हैं:

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

मैंने इसका उपयोग पीएनजी फाइलों को एक यादृच्छिक विवरण से एक अद्वितीय नाम के साथ बचाने के लिए किया।


5

यहाँ पर मैंने अभी क्लिपफ्लेयर ( http://github.com/Zoomicon/ClipFlair ) StringExtensions static class (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)
}

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

1

मुझे इसका उपयोग त्वरित और समझने में आसान लगता है:

<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निर्माता स्ट्रिंग है कि एक लेता है charसरणी।


1

अपनी पुरानी परियोजनाओं से, मुझे यह समाधान मिल गया है, जो 2 वर्षों से पूरी तरह से काम कर रहा है। मैं "" के साथ अवैध वर्णों को प्रतिस्थापित कर रहा हूं, और फिर दोहरे के लिए जांच करूंगा! '

    public string GetSafeFilename(string filename)
    {
        string res = string.Join("!", filename.Split(Path.GetInvalidFileNameChars()));

        while (res.IndexOf("!!") >= 0)
            res = res.Replace("!!", "!");

        return res;
    }

0

कई एएआरवी उपयोग करने का सुझाव देते हैं Path.GetInvalidFileNameChars()जो मुझे एक बुरा समाधान की तरह लगता है। मैं आपको ब्लैक लिस्ट करने के बजाय व्हाइटलाइनिंग का उपयोग करने के लिए प्रोत्साहित करता हूं क्योंकि हैकर्स को हमेशा इसे बायपास करने का एक तरीका मिलेगा।

यहाँ कोड का एक उदाहरण है जिसका आप उपयोग कर सकते हैं:

    string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
    foreach (char c in filename)
    {
        if (!whitelist.Contains(c))
        {
            filename = filename.Replace(c, '-');
        }
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.