C # फ़ाइल नाम को संचित करें


174

मैं हाल ही में विभिन्न स्थानों से एमपी के एक समूह को एक रिपॉजिटरी में स्थानांतरित कर रहा हूं। मैं 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<char>(Path.GetInvalidFileNameChars());
            _BadChars.AddRange(Path.GetInvalidPathChars());
            _BadChars = Utility.GetUnique<char>(_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<string> parts = new List<string>(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());
    }

इस फ़ंक्शन को तेज़ और कम बारोक बनाने के लिए कोई भी सुधार बहुत सराहना की जाएगी।


जवाबों:


314

एक फ़ाइल नाम को साफ करने के लिए आप ऐसा कर सकते हैं

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, "_" );
}

3
प्रश्न पथों के बारे में था, फाइलनामों के बारे में नहीं, और इनके लिए अमान्य वर्ण अलग-अलग हैं।
डोर हाई आर्क

15
हो सकता है, लेकिन इस कोड ने निश्चित रूप से मेरी मदद की जब मुझे एक ही समस्या थी :)
mmr

8
और एक और संभावित महान एसओ उपयोगकर्ता चलते हैं ... यह फ़ंक्शन बहुत अच्छा है। आपको धन्यवाद Adrevdm ...
Dan Rosenstark

19
बड़ी विधि। यद्यपि यह मत भूलो कि आरक्षित शब्द अभी भी तुम्हें काटेंगे, और तुम अपना सिर खुजलाते रह जाओगे। स्रोत: विकिपीडिया फ़ाइल का नाम शब्द सुरक्षित
स्पड

8
यदि फ़ाइल के नाम के अंत में पीरियड्स अमान्य वर्ण हैं तो GetInvalidFileNameCharsउन्हें शामिल नहीं करता है। यह खिड़कियों में एक अपवाद नहीं फेंकता है, यह सिर्फ उन्हें बंद कर देता है, लेकिन यह अप्रत्याशित व्यवहार का कारण बन सकता है यदि आप इस अवधि की उम्मीद कर रहे हैं। मैंने उस मामले को संभालने के लिए regex को संशोधित किया, जिससे कि .यदि वह स्ट्रिंग के अंत में है, तो उसे अमान्य वर्णों में से एक माना जा सकता है।
स्कॉट चैंबरलेन

120

एक छोटा समाधान:

var invalids = System.IO.Path.GetInvalidFileNameChars();
var newName = String.Join("_", origFileName.Split(invalids, StringSplitOptions.RemoveEmptyEntries) ).TrimEnd('.');

1
@PeterMajeed: टीआईएल कि लाइन-काउंटिंग शून्य पर शुरू होती है :-)
गैरी मैकगिल

यह विशेष रूप से ASP.NET कोर के लिए शीर्ष उत्तर से बेहतर है जो मंच के आधार पर विभिन्न वर्णों को वापस कर सकता है।
एलेक्सी

79

आंद्रे के शानदार जवाब के आधार पर लेकिन आरक्षित शब्दों पर स्पॉड की टिप्पणी को ध्यान में रखते हुए, मैंने यह संस्करण बनाया:

/// <summary>
/// Strip illegal chars and reserved words from a candidate filename (should not include the directory path)
/// </summary>
/// <remarks>
/// http://stackoverflow.com/questions/309485/c-sharp-sanitize-file-name
/// </remarks>
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);
}

1
यह एक अत्यंत पूर्ण उत्तर है, कम से कम प्रश्न के फ़ाइल नाम के हिस्से में, और अधिक उत्थान के योग्य है।
ब्रायन मैकके

2
लघु सुझाव चूंकि यह दिखता है कि विधि इस दिशा में जा रही थी: इस कीवर्ड को जोड़ें और यह एक आसान विस्तार विधि बन गई। सार्वजनिक स्थैतिक स्ट्रिंग CoerceValidFileName (यह स्ट्रिंग फ़ाइल नाम)
रेयान मैकआर्थर

2
छोटा बग: यह विधि फ़ाइल एक्सटेंशन (जैसे। COM1) के बिना आरक्षित शब्दों को नहीं बदलती है , जो भी अस्वीकृत हैं। सुझाए गए फ़िक्स को बदलने के "^{0}(\\.|$)"लिए "_reservedWord_$1"
आरक्षितवॉर्डपार्टन


4

मैं का उपयोग कर रहा हूँ System.IO.Path.GetInvalidFileNameChars() अमान्य वर्णों की जाँच करने के विधि और मुझे कोई समस्या नहीं है।

मैं निम्नलिखित कोड का उपयोग कर रहा हूं:

foreach( char invalidchar in System.IO.Path.GetInvalidFileNameChars())
{
    filename = filename.Replace(invalidchar, '_');
}

3

मैं पात्रों को किसी तरह से बनाए रखना चाहता था, न कि केवल चरित्र को एक अंडरस्कोर के साथ बदलना।

एक तरीका मुझे लगा कि पात्रों को समान दिखने वाले पात्रों के साथ बदलना है (जो मेरी स्थिति में हैं), नियमित पात्रों के रूप में उपयोग किए जाने की संभावना नहीं है। इसलिए मैंने अमान्य वर्णों की सूची ली और लुक-ए-लाइक पाया।

निम्नलिखित लुक-ए-पसंद के साथ सांकेतिक शब्दों में बदलना और डिकोड करने के लिए कार्य हैं।

इस कोड में सभी System.IO.Path.GetInvalidFileNameChars () वर्णों के लिए पूरी सूची शामिल नहीं है। तो यह आप पर निर्भर है कि किसी भी शेष वर्ण के लिए अंडरस्कोर रिप्लेसमेंट का विस्तार या उपयोग करें।

private static Dictionary<string, string> EncodeMapping()
{
    //-- Following characters are invalid for windows file and folder names.
    //-- \/:*?"<>|
    Dictionary<string, string> dic = new Dictionary<string, string>();
    dic.Add(@"\", "Ì"); // U+OOCC
    dic.Add("/", "Í"); // U+OOCD
    dic.Add(":", "¦"); // U+00A6
    dic.Add("*", "¤"); // U+00A4
    dic.Add("?", "¿"); // U+00BF
    dic.Add(@"""", "ˮ"); // U+02EE
    dic.Add("<", "«"); // U+00AB
    dic.Add(">", "»"); // U+00BB
    dic.Add("|", "│"); // U+2502
    return dic;
}

public static string Escape(string name)
{
    foreach (KeyValuePair<string, string> replace in EncodeMapping())
    {
        name = name.Replace(replace.Key, replace.Value);
    }

    //-- handle dot at the end
    if (name.EndsWith(".")) name = name.CropRight(1) + "°";

    return name;
}

public static string UnEscape(string name)
{
    foreach (KeyValuePair<string, string> replace in EncodeMapping())
    {
        name = name.Replace(replace.Value, replace.Key);
    }

    //-- handle dot at the end
    if (name.EndsWith("°")) name = name.CropRight(1) + ".";

    return name;
}

आप अपने लुक-ए-पसंद का चयन कर सकते हैं। मैंने खदान चुनने के लिए खिड़कियों में कैरेक्टर मैप ऐप का इस्तेमाल किया%windir%\system32\charmap.exe

जैसा कि मैंने खोज के माध्यम से समायोजन किया है, मैं इस कोड को अपडेट करूंगा।


ध्यान दें कि ऐसे कई अक्षर हैं, जो उन जैसे ही मिलते-जुलते हैं, जैसे कि फुलवॉर्शन फॉर्म !"#$%&'()*+,-./:;<=>?@{|}~ या उनके अन्य रूप जैसे /SOLIDUS और `⁄` फ्रैक्शन SLASH, जिन्हें बिना किसी समस्या के सीधे फ़ाइल नाम में इस्तेमाल किया जा सकता है
phuclv

2

मुझे लगता है कि समस्या यह है कि आप पहले Path.GetDirectoryNameखराब स्ट्रिंग पर कॉल करें । यदि इसमें गैर-फ़ाइल नाम अक्षर हैं, तो .net यह नहीं बता सकते कि स्ट्रिंग के कौन से हिस्से निर्देशिका और थ्रो हैं। आपको स्ट्रिंग तुलना करना होगा।

यह मानते हुए कि यह केवल फ़ाइल नाम है जो खराब है, संपूर्ण पथ नहीं, यह प्रयास करें:

public static string SanitizePath(string path, char replaceChar)
{
    int filenamePos = path.LastIndexOf(Path.DirectorySeparatorChar) + 1;
    var sb = new System.Text.StringBuilder();
    sb.Append(path.Substring(0, filenamePos));
    for (int i = filenamePos; i < path.Length; i++)
    {
        char filenameChar = path[i];
        foreach (char c in Path.GetInvalidFileNameChars())
            if (filenameChar.Equals(c))
            {
                filenameChar = replaceChar;
                break;
            }

        sb.Append(filenameChar);
    }

    return sb.ToString();
}

2

मुझे अतीत में इसके साथ सफलता मिली है।

अच्छा, छोटा और स्थिर :-)

    public static string returnSafeString(string s)
    {
        foreach (char character in Path.GetInvalidFileNameChars())
        {
            s = s.Replace(character.ToString(),string.Empty);
        }

        foreach (char character in Path.GetInvalidPathChars())
        {
            s = s.Replace(character.ToString(), string.Empty);
        }

        return (s);
    }

2

यहां बहुत सारे कार्यशील समाधान हैं। पूर्णता के लिए, यहाँ एक दृष्टिकोण है जो रेगेक्स का उपयोग नहीं करता है, लेकिन LINQ का उपयोग करता है:

var invalids = Path.GetInvalidFileNameChars();
filename = invalids.Aggregate(filename, (current, c) => current.Replace(c, '_'));

इसके अलावा, यह एक बहुत ही कम समाधान है;)


1
मुझे एक लाइनर से प्यार है :)
लैरी

1

यहाँ आंद्रे के कोड के आधार पर एक कुशल आलसी लोडिंग विस्तार विधि है:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LT
{
    public static class Utility
    {
        static string invalidRegStr;

        public static string MakeValidFileName(this string name)
        {
            if (invalidRegStr == null)
            {
                var invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
                invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);
            }

            return System.Text.RegularExpressions.Regex.Replace(name, invalidRegStr, "_");
        }
    }
}

0

यदि आप निर्देशिका और फ़ाइल नाम को एक साथ जोड़ते हैं और उन्हें स्वतंत्र रूप से साफ़ करने की बजाय स्वच्छता करते हैं तो आपका कोड क्लीनर होगा। के रूप में दूर sanitizing के लिए:, बस स्ट्रिंग में 2 चरित्र ले। यदि यह "प्रतिस्थापनकर्ता" के बराबर है, तो इसे एक बृहदान्त्र के साथ बदलें। चूंकि यह ऐप आपके स्वयं के उपयोग के लिए है, ऐसे समाधान पूरी तरह से पर्याप्त होना चाहिए।


-1
using System;
using System.IO;
using System.Linq;
using System.Text;

public class Program
{
    public static void Main()
    {
        try
        {
            var badString = "ABC\\DEF/GHI<JKL>MNO:PQR\"STU\tVWX|YZA*BCD?EFG";
            Console.WriteLine(badString);
            Console.WriteLine(SanitizeFileName(badString, '.'));
            Console.WriteLine(SanitizeFileName(badString));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    private static string SanitizeFileName(string fileName, char? replacement = null)
    {
        if (fileName == null) { return null; }
        if (fileName.Length == 0) { return ""; }

        var sb = new StringBuilder();
        var badChars = Path.GetInvalidFileNameChars().ToList();

        foreach (var @char in fileName)
        {
            if (badChars.Contains(@char)) 
            {
                if (replacement.HasValue)
                {
                    sb.Append(replacement.Value);
                }
                continue; 
            }
            sb.Append(@char);
        }
        return sb.ToString();
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.