পাথ.কোমাইন সঠিকভাবে প্যাট.ডাইরেক্টরিসপেটরচারের সাথে শুরু হওয়া ফাইলের নামগুলি সংযুক্ত করে না কেন?


181

ভিজ্যুয়াল স্টুডিওর তাত্ক্ষণিক উইন্ডো থেকে :

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

মনে হয় তাদের উভয়ই এক হওয়া উচিত।

পুরানো ফাইলসিস্টেমবজেক্ট.বিল্ডপথ () এভাবে কাজ করে নি ...



@ জো, বোকা ঠিক! এছাড়াও, আমার অবশ্যই উল্লেখ করতে হবে যে নোড.জেএসে সমতুল্য ফাংশন ঠিকঠাক কাজ করে ... মাইক্রোসফ্টে আমার মাথা কাঁপানো ...
এনএইচ।

2
। নেট কোর / স্ট্যান্ডার্ডের জন্য @zwcloud Path.Combine()মূলত পিছনের সামঞ্জস্যের জন্য (বিদ্যমান আচরণের সাথে)। আপনি এই ব্যবহারটি আরও ভাল করবেন Path.Join(): "সম্মিলন পদ্ধতির বিপরীতে, জোড় পদ্ধতিটি ফিরে আসা পথটিকে রুট করার চেষ্টা করে না ( পদ্ধতিটি করে)) "
স্টেজ

উত্তর:


201

এটি একটি দার্শনিক প্রশ্ন (যা সম্ভবত কেবল মাইক্রোসফ্ট সত্যই উত্তর দিতে পারে), যেহেতু এটি ডকুমেন্টেশন যা বলে ঠিক তাই করছে।

System.IO.Path.Combine

"যদি পথ 2 একটি পরম পাথ থাকে, এই পদ্ধতিটি পথ 2 ফেরত দেয়।"

.NET উত্স থেকে আসল সম্মিলন পদ্ধতিটি এখানে । আপনি দেখতে পাচ্ছেন যে এটি কম্বাইননোচেকসকে কল করে , যা পরে প্যাস 2 এ ইসপথরোডকে কল করে এবং যদি সেই পথে ফিরে আসে:

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
আমি এই ট্রিমটি পছন্দসই এফেক্ট স্ট্রিং স্ট্রফিলপথ = পাথ.কোমাইন (বেসপথ, অন্যান্যপ্যাথ.ট্রিমস্টার্ট (নতুন চর [] char '\\', '/'})) পেতে ব্যবহার করি;
ম্যাথু লক

3
আমি আমার ওয়ার্কিং কোডটি Path.Combineকেবল নিরাপদ হিসাবে পরিবর্তন করেছিলাম তবে তা ভেঙে যায় .. এটি এত বোকা :)
সোমেন

23

এটি पथ.কোমাইন পদ্ধতির জন্য .NET রিফ্লেক্টর থেকে বিচ্ছিন্ন কোড । ইসপথরোটেড ফাংশনটি পরীক্ষা করুন। যদি দ্বিতীয় পথটি মূলযুক্ত হয় (ডিরেক্টরিটিপ্রেটারচর দিয়ে শুরু হয়), দ্বিতীয় পথটি যেমন রয়েছে তেমন ফিরে আসুন।

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 "টিকে ড্রাইভ লেটারটি অনুপস্থিত থাকা সত্ত্বেও" পরম "হিসাবে বিবেচনা করা হয়। আমার মতে সঠিক আচরণটি হ'ল দ্বিতীয় পথটি ডিরেক্টরি বিভাজক (এবং কোনও ইউএনসি পাথ নয়) দিয়ে শুরু হওয়ার সাথে সাথে প্রথম পাথ থেকে ড্রাইভ লেটারটি প্রিপেন্ড করা হবে। আমি আপনার নিজের সহায়ক র্যাপার ফাংশনটি লেখার সুপারিশ করব যা আপনার প্রয়োজন হলে আপনার ইচ্ছা মতো আচরণ করে।


7
এটি অনুমানের সাথে মেলে তবে এটি আমি যা প্রত্যাশা করতাম তা নয়।
dthrasher

@ জেক এটি কোনও বাগফিক্স এড়ছে না; এটি বেশিরভাগ লোকেরা কীভাবে কীভাবে করবেন সে সম্পর্কে দীর্ঘ এবং কঠোর চিন্তাভাবনা করে এবং তারপরে তারা যে বিষয়ে সম্মত হয় তার প্রতি আঁকড়ে থাকে। এছাড়াও। নেট ফ্রেমওয়ার্ক (একটি গ্রন্থাগার রয়েছে যা Path.Combine) এবং সি # ভাষার মধ্যে পার্থক্যটি নোট করুন ।
গ্রেট

9

এমএসডিএন থেকে :

যদি নির্দিষ্ট পাথগুলির মধ্যে একটি শূন্য-দৈর্ঘ্যের স্ট্রিং হয় তবে এই পদ্ধতিটি অন্য পথটি ফেরত দেয়। যদি পথ 2 একটি পরম পাথ থাকে, এই পদ্ধতিটি পথ 2 ফেরায়।

আপনার উদাহরণে, পথ 2 পরম।


7

"মাইক্রোসফ্ট সম্পর্কে আমি ঘৃণা করি" ব্লগের " পাথ.কোমাইন মূলত নিরর্থক led " শীর্ষক ব্লগটিতে খ্রিস্টান গ্রাসের পরামর্শ অনুসরণ করে , এখানে আমার সমাধানটি দেওয়া হয়েছে:

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'

এর অর্থ এই যে আপনি যখন পূর্ববর্তী স্ল্যাশ সহ কোনও পথে যোগদান করেন, আপনি আসলে একটি বেসে অন্য বেসে যোগ দিচ্ছেন, সেক্ষেত্রে দ্বিতীয়টি প্রাধান্য পায়।


আমি মনে করি ফরোয়ার্ড স্ল্যাশগুলি ব্যাখ্যা করা উচিত। এছাড়াও, নেট। এর সাথে এটির কী আছে?
পিটার মর্টেনসেন

3

কারণ:

আপনার দ্বিতীয় ইউআরএলটিকে একটি পরম পথ হিসাবে বিবেচনা করা হয়, 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);

উভয় ক্ষেত্রেই "সি: \ পরীক্ষা \ পরীক্ষা" ফেরত আসে।

প্রথমে, আমি মূল্যায়ন করি / যদি পথ 2 দিয়ে শুরু হয় / এবং এটি সত্য হয় তবে প্রথম অক্ষর ছাড়াই পাথ 2 ফিরিয়ে দিন। অন্যথায়, পুরো পথ 2 ফেরান।


1
কল হিসাবে == @"\"চেকটি প্রতিস্থাপন করা সম্ভবত এটি নিরাপদ Path.IsRooted()কারণ "\"এটি কেবলমাত্র অক্ষর নয়।
rumblefx0

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: \ পরীক্ষা" এর সমান হতে পারে।



0

আমি নীচের মতো পথগুলিকে একত্রিত করার জন্য সামগ্রিক ফাংশন ব্যবহার করেছি:

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

0

রায়ান উল্লিখিত হিসাবে এটি ডকুমেন্টেশন যা বলে ঠিক তাই করছে।

ডস বার থেকে, বর্তমান ডিস্ক এবং বর্তমান পথ পৃথক করা হয়। \মূল পাথ, তবে বর্তমান ডিস্কের জন্য।

প্রতিটি " ডিস্ক " এর জন্য পৃথক " বর্তমান পথ " থাকে। আপনি যদি ডিস্কটি ব্যবহার করে পরিবর্তন করেন তবে আপনি cd D:বর্তমান পথটি পরিবর্তন করবেন নাD:\ , তবে: "D: \ যাই হোক না কেন \ এই \ ডিস্কটিতে \ শেষ \ পথ \ অ্যাক্সেস করা হয়েছিল" ...

সুতরাং, উইন্ডোগুলিতে, আক্ষরিক @"\x"অর্থ: "CURRENTDISK: \ x"। সুতরাং Path.Combine(@"C:\x", @"\y")দ্বিতীয় প্যারামিটার হিসাবে একটি মূল পাথ রয়েছে, কোনও আত্মীয় নয় যদিও জানা ডিস্কে নেই ... এবং যেহেতু এটি «বর্তমান ডিস্ক be হতে পারে তা জানা যায়নি, তাই পাইথন প্রত্যাবর্তন করে "\\y"

>cd C:
>cd \mydironC\apath
>cd D:
>cd \mydironD\bpath
>cd C:
>cd
>C:\mydironC\apath
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.