Path.Combine PathDirectorySeparatorChar के साथ शुरू होने वाले फ़ाइल नाम को ठीक से नहीं करता है?


186

से तत्काल विंडो दृश्य स्टूडियो में:

> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"

ऐसा लगता है कि वे दोनों एक ही होने चाहिए।

पुराना FileSystemObject.BuildPath () इस तरह से काम नहीं किया ...



@ जो, बेवकूफ सही है! इसके अलावा, मुझे यह भी बताना चाहिए कि समतुल्य फ़ंक्शन नोड में ठीक काम करता है। जेएस ... माइक्रोसॉफ्ट में मेरा सिर हिला रहा है ...
एनएच।

2
.NET कोर / स्टैंडर्ड के लिए @zwcloud, Path.Combine()मुख्य रूप से पश्चगामी संगतता (मौजूदा व्यवहार के साथ) के लिए है। आप का उपयोग करना बेहतर होगा Path.Join(): "कम्बाइन विधि के विपरीत, ज्वाइन विधि लौटे पथ को रूट करने का प्रयास नहीं करती है। (अर्थात, यदि path2 एक निरपेक्ष पथ है, तो Join विधि path1 को नहीं छोड़ती है और path2 को Combine के रूप में वापस करती है। विधि करता है।) "
स्टैज

जवाबों:


205

यह एक दार्शनिक प्रश्न है (जो शायद केवल Microsoft वास्तव में उत्तर दे सकता है), क्योंकि यह वही है जो प्रलेखन कहता है।

System.IO.Path.Combine

"यदि पथ 2 में कोई निरपेक्ष पथ है, तो यह विधि पथ 2 को लौटाती है।"

यहां .NET कंबाइन से वास्तविक कंबाइन विधि दी गई है। आप देख सकते हैं कि यह CombineNoChecks को कॉल करता है , जो तब पथ 2 पर IsPathRooted को कॉल करता है और यदि आपको यह रिटर्न मिलता है:

public static String Combine(String path1, String path2) {
    if (path1==null || path2==null)
        throw new ArgumentNullException((path1==null) ? "path1" : "path2");
    Contract.EndContractBlock();
    CheckInvalidPathChars(path1);
    CheckInvalidPathChars(path2);

    return CombineNoChecks(path1, path2);
}

internal static string CombineNoChecks(string path1, string path2)
{
    if (path2.Length == 0)
        return path1;

    if (path1.Length == 0)
        return path2;

    if (IsPathRooted(path2))
        return path2;

    char ch = path1[path1.Length - 1];
    if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar &&
            ch != VolumeSeparatorChar) 
        return path1 + DirectorySeparatorCharAsString + path2;
    return path1 + path2;
}

मैं नहीं जानता कि तर्क क्या है। मुझे लगता है कि समाधान दूसरे पथ की शुरुआत से (या ट्रिम) डायरेक्ट्रीसेपरेटर को बंद करना है; हो सकता है कि अपनी खुद की कम्बाइन विधि लिखें जो ऐसा करता है और फिर Path.Combine () कहता है।


असंतुष्ट कोड (मेरी पोस्ट की जांच करें) को देखते हुए, आप एक तरह से सही हैं।
गुलज़ार नाज़िम

7
मुझे लगता है कि यह उस तरह से काम करता है जिससे "वर्तमान कार्यशील डीआईआर" एल्गोरिदम तक आसान पहुंच की अनुमति मिलती है।
बीसीएस

यह cd (component)कमांड लाइन से एक अनुक्रम करने की तरह काम करता है । मेरे लिए उचित लगता है।
एड्रियन रत्नापला

11
मैं वांछित प्रभाव स्ट्रिंग strFilePath = Path.Combine (basePath, otherPath.TrimStart (नया char [] {'\\', '/'})) प्राप्त करने के लिए इस ट्रिम का उपयोग करता हूं;
मैथ्यू लॉक

3
मैंने अपना कामकाजी कोड Path.Combineसिर्फ सुरक्षित होने के लिए बदल दिया, लेकिन फिर वह टूट गया .. यह बहुत बेवकूफाना है :)
sotn

23

यह Path.Combine विधि के लिए .NET रिफलेक्टर से डिसबेल्ड कोड है । चेक IsPathRooted फ़ंक्शन। यदि दूसरा रास्ता रूट किया गया है (एक DirectorySeparatorChar से शुरू होता है), तो दूसरा रास्ता लौटाएँ।

public static string Combine(string path1, string path2)
{
    if ((path1 == null) || (path2 == null))
    {
        throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
    }
    CheckInvalidPathChars(path1);
    CheckInvalidPathChars(path2);
    if (path2.Length == 0)
    {
        return path1;
    }
    if (path1.Length == 0)
    {
        return path2;
    }
    if (IsPathRooted(path2))
    {
        return path2;
    }
    char ch = path1[path1.Length - 1];
    if (((ch != DirectorySeparatorChar) &&
         (ch != AltDirectorySeparatorChar)) &&
         (ch != VolumeSeparatorChar))
    {
        return (path1 + DirectorySeparatorChar + path2);
    }
    return (path1 + path2);
}


public static bool IsPathRooted(string path)
{
    if (path != null)
    {
        CheckInvalidPathChars(path);
        int length = path.Length;
        if (
              (
                  (length >= 1) &&
                  (
                      (path[0] == DirectorySeparatorChar) ||
                      (path[0] == AltDirectorySeparatorChar)
                  )
              )

              ||

              ((length >= 2) &&
              (path[1] == VolumeSeparatorChar))
           )
        {
            return true;
        }
    }
    return false;
}

23

मैं इस समस्या को हल करना चाहता था:

string sample1 = "configuration/config.xml";
string sample2 = "/configuration/config.xml";
string sample3 = "\\configuration/config.xml";

string dir1 = "c:\\temp";
string dir2 = "c:\\temp\\";
string dir3 = "c:\\temp/";

string path1 = PathCombine(dir1, sample1);
string path2 = PathCombine(dir1, sample2);
string path3 = PathCombine(dir1, sample3);

string path4 = PathCombine(dir2, sample1);
string path5 = PathCombine(dir2, sample2);
string path6 = PathCombine(dir2, sample3);

string path7 = PathCombine(dir3, sample1);
string path8 = PathCombine(dir3, sample2);
string path9 = PathCombine(dir3, sample3);

बेशक, सभी पथ 1-9 में अंत में एक समतुल्य स्ट्रिंग होनी चाहिए। यहाँ पाथकोम्बाइन विधि है जिसके साथ मैं आया था:

private string PathCombine(string path1, string path2)
{
    if (Path.IsPathRooted(path2))
    {
        path2 = path2.TrimStart(Path.DirectorySeparatorChar);
        path2 = path2.TrimStart(Path.AltDirectorySeparatorChar);
    }

    return Path.Combine(path1, path2);
}

मुझे यह भी लगता है कि यह काफी कष्टप्रद है कि इस स्ट्रिंग हैंडलिंग को मैन्युअल रूप से किया जाना है, और मुझे इसके पीछे कारण में दिलचस्पी होगी।


19

मेरी राय में यह एक बग है। समस्या यह है कि "निरपेक्ष" पथ के दो अलग-अलग प्रकार हैं। पथ "d: \ mydir \ myfile.txt" निरपेक्ष है, पथ "mydir \ myfile.txt" को ड्राइव अक्षर गुम होने के बावजूद भी "पूर्ण" माना जाता है। मेरे विचार में सही व्यवहार, ड्राइव लेटर को पहले पथ से प्रीपेंड करना होगा जब दूसरा रास्ता डायरेक्टरी सेपरेटर (और UNC पथ नहीं है) से शुरू होता है। मैं आपको अपना खुद का हेल्पर रैपर फ़ंक्शन लिखने की सलाह दूंगा जिसमें आपकी ज़रूरत के अनुसार व्यवहार हो।


7
यह कल्पना से मेल खाता है, लेकिन यह वह नहीं है जिसकी मुझे उम्मीद थी।
धर्मर

@ जेक एक बगफिक्स से परहेज नहीं है; कि कई लोग लंबे और कठिन सोच रहे हैं कि कैसे कुछ करना है, और फिर वे जो भी सहमत हैं उससे चिपके रहते हैं। इसके अलावा, .Net फ्रेमवर्क (एक पुस्तकालय जिसमें शामिल है Path.Combine) और C # भाषा के बीच अंतर पर ध्यान दें ।
अंगूर

9

से MSDN :

यदि निर्दिष्ट पथों में से एक शून्य-लंबाई वाला स्ट्रिंग है, तो यह विधि अन्य पथ को लौटाती है। यदि path2 में कोई निरपेक्ष पथ है, तो यह विधि path2 देता है।

आपके उदाहरण में, path2 निरपेक्ष है।


7

क्रिश्चियन ग्रेस की सलाह के बाद " पाथ्स आई हेट विद माइक्रोसॉफ्ट" ब्लॉग जिसका शीर्षक है " Path.Combine अनिवार्य रूप से बेकार है। ", यहाँ मेरा समाधान है:

public static class Pathy
{
    public static string Combine(string path1, string path2)
    {
        if (path1 == null) return path2
        else if (path2 == null) return path1
        else return path1.Trim().TrimEnd(System.IO.Path.DirectorySeparatorChar)
           + System.IO.Path.DirectorySeparatorChar
           + path2.Trim().TrimStart(System.IO.Path.DirectorySeparatorChar);
    }

    public static string Combine(string path1, string path2, string path3)
    {
        return Combine(Combine(path1, path2), path3);
    }
}

कुछ सलाह देते हैं कि नाम स्थान से टकरा जाना चाहिए, ... मैं Pathyएक मामूली के रूप में, और साथ नामस्थान टकराव से बचने के लिए गया System.IO.Path

संपादित करें : जोड़ा गया शून्य पैरामीटर जांच


4

इस कोड को चाल करना चाहिए:

        string strFinalPath = string.Empty;
        string normalizedFirstPath = Path1.TrimEnd(new char[] { '\\' });
        string normalizedSecondPath = Path2.TrimStart(new char[] { '\\' });
        strFinalPath =  Path.Combine(normalizedFirstPath, normalizedSecondPath);
        return strFinalPath;

4

वास्तविक विवरणों को न जानकर, मेरा अनुमान है कि यह आप जैसे रिश्तेदार यूआरआई से जुड़ सकता है, वैसे ही जुड़ने का प्रयास करता है। उदाहरण के लिए:

urljoin('/some/abs/path', '../other') = '/some/abs/other'

इसका मतलब यह है कि जब आप पूर्ववर्ती स्लेश के साथ एक पथ से जुड़ते हैं, तो आप वास्तव में एक आधार से दूसरे में शामिल हो रहे होते हैं, जिस स्थिति में दूसरा पूर्ववर्ती हो जाता है।


मुझे लगता है कि आगे की स्लैश को समझाया जाना चाहिए। इसके अलावा, .NET के साथ इसका क्या करना है?
पीटर मोर्टेंसन

3

कारण:

आपका दूसरा URL एक पूर्ण पथ माना जाता है, Combine यदि अंतिम पथ विधि केवल अंतिम पथ लौटाएगी।

समाधान: बस /अपने दूसरे पथ ( /SecondPathको SecondPath) के शुरुआती स्लैश को हटा दें । फिर यह आपके अलावा काम करता है।


3

यह वास्तव में समझ में आता है, किसी तरह से, कैसे (रिश्तेदार) रास्तों पर विचार किया जाता है:

string GetFullPath(string path)
{
     string baseDir = @"C:\Users\Foo.Bar";
     return Path.Combine(baseDir, path);
}

// Get full path for RELATIVE file path
GetFullPath("file.txt"); // = C:\Users\Foo.Bar\file.txt

// Get full path for ROOTED file path
GetFullPath(@"C:\Temp\file.txt"); // = C:\Temp\file.txt

असली सवाल यह है: "\""मूल" माने जाने वाले रास्ते क्यों शुरू होते हैं ? यह मेरे लिए भी नया था, लेकिन यह विंडोज पर इस तरह से काम करता है :

new FileInfo("\windows"); // FullName = C:\Windows, Exists = True
new FileInfo("windows"); // FullName = C:\Users\Foo.Bar\Windows, Exists = False

1

यदि आप किसी भी रास्ते को खोए बिना दोनों रास्तों को मिलाना चाहते हैं तो आप इसका उपयोग कर सकते हैं:

?Path.Combine(@"C:\test", @"\test".Substring(0, 1) == @"\" ? @"\test".Substring(1, @"\test".Length - 1) : @"\test");

या चर के साथ:

string Path1 = @"C:\Test";
string Path2 = @"\test";
string FullPath = Path.Combine(Path1, Path2.IsRooted() ? Path2.Substring(1, Path2.Length - 1) : Path2);

दोनों मामले "C: \ test \ test" लौटाते हैं।

सबसे पहले, मैं मूल्यांकन करता हूं कि क्या Path2 के साथ शुरू होता है / और अगर यह सच है, पहले अक्षर के बिना Path2 वापस करें। अन्यथा, पूर्ण पथ 2 को वापस करें।


1
यह शायद == @"\"एक Path.IsRooted()कॉल द्वारा चेक को बदलने के लिए सुरक्षित है क्योंकि "\"इसके लिए एकमात्र चरित्र नहीं है।
रंबलफैक्स 0

0

इन दो तरीकों से आपको गलती से दो तारों में शामिल होने से बचाना चाहिए कि दोनों में सीमांकक है।

    public static string Combine(string x, string y, char delimiter) {
        return $"{ x.TrimEnd(delimiter) }{ delimiter }{ y.TrimStart(delimiter) }";
    }

    public static string Combine(string[] xs, char delimiter) {
        if (xs.Length < 1) return string.Empty;
        if (xs.Length == 1) return xs[0];
        var x = Combine(xs[0], xs[1], delimiter);
        if (xs.Length == 2) return x;
        var ys = new List<string>();
        ys.Add(x);
        ys.AddRange(xs.Skip(2).ToList());
        return Combine(ys.ToArray(), delimiter);
    }

0

यह \ "वर्तमान ड्राइव की मूल निर्देशिका" का अर्थ है। आपके उदाहरण में इसका अर्थ है वर्तमान ड्राइव के रूट डायरेक्टरी में "टेस्ट" फ़ोल्डर। तो, यह "c: \ test" के बराबर हो सकता है।



0

मैंने नीचे के रूप में संयोजन के लिए मजबूर करने के लिए कुल फ़ंक्शन का उपयोग किया:

public class MyPath    
{
    public static string ForceCombine(params string[] paths)
    {
        return paths.Aggregate((x, y) => Path.Combine(x, y.TrimStart('\\')));
    }
}

0

जैसा कि रेयान ने उल्लेख किया है कि यह वही है जो प्रलेखन कहता है।

डॉस समय से, वर्तमान डिस्क और वर्तमान पथ प्रतिष्ठित हैं। \रूट पथ है, लेकिन CURRENT DISK के लिए।

प्रत्येक " डिस्क " के लिए एक अलग " वर्तमान पथ " है। यदि आप डिस्क का उपयोग करके बदलते cd D:हैं तो आप वर्तमान पथ को नहीं बदलते हैंD:\ , लेकिन: "D: \ \ \ \ the \ last \ path \ access \ on \ this \ डिस्क" ...

तो, विंडोज़ में, एक शाब्दिक @"\x"अर्थ है: "CURRENTDISK: \ x"। इसलिए Path.Combine(@"C:\x", @"\y")दूसरे पैरामीटर के रूप में एक रूट पथ है, एक रिश्तेदार नहीं, हालांकि एक ज्ञात डिस्क में नहीं है ... और चूंकि यह ज्ञात नहीं है कि «चालू डिस्क», अजगर रिटर्न हो सकता है "\\y"

>cd C:
>cd \mydironC\apath
>cd D:
>cd \mydironD\bpath
>cd C:
>cd
>C:\mydironC\apath
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.