.net - 取得 - visual studio path combine




ルートを基準にしたパスの計算-Path.Combineの逆数 (3)

Path.Combine()の逆数を計算する信頼できる方法はありますか?

Path.Combine( "c:\ folder"、 "subdirectory \ something.txt")は、 "c:\ folder \ subdirectory \ something.text"のようなものを返します。 私が望むのは逆です。Path.GetRelativeUrl( "c:\ folder"、 "c:\ folder \ subdirectory \ something.text")はサブディレクトリ\ something.txtのようなものを返します。

1つの解決策は、文字列の比較を行い、根をトリムすることですが、同じパスが異なる方法(パス式では ".."または "〜1"の使用)で表現されている場合は機能しません。


最初にPath.GetFullPathを試してから、文字列の比較を行います。


申し訳ありませんが、私のケースでは、厳しいエッジケース(fullPathとrelativePathミックスネットワークマップの場所、超長いファイル名)がありません。 私がやったことは、以下のクラスを作成することでした

public class PathUtil
{
    static public string NormalizeFilepath(string filepath)
    {
        string result = System.IO.Path.GetFullPath(filepath).ToLowerInvariant();

        result = result.TrimEnd(new [] { '\\' });

        return result;
    }

    public static string GetRelativePath(string rootPath, string fullPath)
    {
        rootPath = NormalizeFilepath(rootPath);
        fullPath = NormalizeFilepath(fullPath);

        if (!fullPath.StartsWith(rootPath))
            throw new Exception("Could not find rootPath in fullPath when calculating relative path.");

        return "." + fullPath.Substring(rootPath.Length);
    }
}

それはかなりうまくいくようです。 少なくとも、これらのNUnitテストに合格します:

[TestFixture]
public class PathUtilTest
{
    [Test]
    public void TestDifferencesInCapitolizationDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\WindowS\\System32");

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestDifferencesDueToBackstepsDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\Program Files\\..\\Windows\\System32");

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestDifferencesInFinalSlashDontMatter()
    {
        string format1 = PathUtil.NormalizeFilepath("c:\\windows\\system32");
        string format2 = PathUtil.NormalizeFilepath("c:\\windows\\system32\\");

        Console.WriteLine(format1);
        Console.WriteLine(format2);

        Assert.AreEqual(format1, format2);
    }

    [Test]
    public void TestCanCalculateRelativePath()
    {
        string rootPath = "c:\\windows";
        string fullPath = "c:\\windows\\system32\\wininet.dll";
        string expectedResult = ".\\system32\\wininet.dll";

        string result = PathUtil.GetRelativePath(rootPath, fullPath);

        Assert.AreEqual(expectedResult, result);
    }

    [Test]
    public void TestThrowsExceptionIfRootDoesntMatchFullPath()
    {
        string rootPath = "c:\\windows";
        string fullPath = "c:\\program files\\Internet Explorer\\iexplore.exe";

        try
        {
            PathUtil.GetRelativePath(rootPath, fullPath);
        }
        catch (Exception)
        {
            return;
        }

        Assert.Fail("Exception expected");
    }
}

テストケースは既存の特定のファイルに依存しています。これらのファイルはほとんどのWindowsインストールで共通していますが、あなたのマイレージは異なる場合があります。


私は長いファイルパスでこれを行う方法を見つけようとしましたが、標準ファイルシステムコールの長いパスバージョンを使用するとWin32でパスの正規化が失われるため、満足のいく結果が得られません。 だから、この解決法は260文字以上のものでは必ずしも機能しませんが、そうでなければ管理コードと脳死です。

string path1 = @"c:\folder\subdirectory\something.text";
string path2 = @"c:\folder\foo\..\something.text";
Uri value = new Uri(path1);
Uri value2 = new Uri(path2);
Uri result = value.MakeRelativeUri(value2);
Console.WriteLine(result.OriginalString);

それは与える

../something.text

現在、パスの8.3の名前(短い名前)は別の問題です。 これらのパスはファイルシステムに保存されているため、win32を使用して取得する必要があります。 プラス彼らは無効にすることができますので、そこにいるという保証はありません。 ショートパスから長いパスを取得するには、Kernel32.dllのGetLongPathNameを呼び出します。 これは、ファイルが存在しなければならないことを意味します。

あなたがそれをしたい場合、このサイトはあなたの友人です。 GetLongPathName







path