yotiky Tech Blog

とあるエンジニアの備忘録

C# - シンボリックリンクを操作する

TL;DR

.NET 6 でDirectoryクラスにCreateSymbolikLinkメソッドが追加されたため、6以降ではバッチやProcessを使わなくても C# で直接シンボリックリンクを作成できるようになりました。
この記事はディレクトリを対象としていますが、ファイルを対象としたFileクラスとFileInfoクラスも同じように操作可能です。

.NET 5 以前は以下を参照。

yotiky.hatenablog.com

目次

適用対象

  • .NET 6 以降

シンボリックリンクの操作

作成する

DirectoryクラスのCreateSymbolicLinkを使用する。

    var src =   @"C:\Workspace\SymLinkWork\folder1";
    var dest2 = @"C:\Workspace\SymLinkWork\folder2";

    Directory.CreateSymbolicLink(dest2, src);

learn.microsoft.com

ほかに、DiretoryInfoクラスからCreateAsSymbolickLinkを使う方法もある。

    var info = new DirectoryInfo(dest2);
    info.CreateAsSymbolicLink(src);

リンク先を取得する

DirectoryクラスのResolveLinkTargetを使用する。

    var src =   @"C:\Workspace\SymLinkWork\folder1";
    var dest2 = @"C:\Workspace\SymLinkWork\folder2";
    var dest3 = @"C:\Workspace\SymLinkWork\folder3";

    Directory.CreateSymbolicLink(dest2, src);
    Directory.CreateSymbolicLink(dest3, dest2);

    Directory.ResolveLinkTarget(dest3 , false).Dump();
    Directory.ResolveLinkTarget(dest3 , true).Dump();

上がfalse、下がtrueの結果。

returnFinalTargetfalse にすると、直接のリンク先を取得する。 true を指定すると、リンク先がシンボリックリンクだった場合、リンクをたどって最後のリンク先を取得する。

learn.microsoft.com

ほかに、DiretoryInfoクラスからResolveLinkTargetを使う方法もある。

    var info = new DirectoryInfo(dest2);
    info.ResolveLinkTarget(true);

削除する

ディレクトリを消すだけ。

    Directory.Delete(dest2);

指定したディレクトリ配下のシンボリックリンクを確認にする

    var dirs = Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories);
    dirs.Select(path => new DirectoryInfo(path))
        .Select(info => new { Path = info.FullName, Symlink = info.LinkTarget != null, Link = info.LinkTarget })
        .Dump("LinkList");

検証に使用したコード全文(LINQPad)

void Main()
{
    var root = @"C:\Workspace\SymLinkWork";
    var src =   @"C:\Workspace\SymLinkWork\folder1";
    var dest2 = @"C:\Workspace\SymLinkWork\folder2";
    var dest3 = @"C:\Workspace\SymLinkWork\folder3";

    CreateSymlink(dest2, src);
    CreateSymlinkByInfo(dest3, dest2);

    Resolve(dest3, false);
    Resolve(dest3, true);
    ResolveByInfo(dest2, true);

    GetSymLinkList(root);

    DeleteSymlink(dest2);
    DeleteSymlink(dest3);

    GetSymLinkList(root);
}

void CreateSymlink(string dest, string src)
{
    Directory.CreateSymbolicLink(dest, src).Dump("Create");
}
void CreateSymlinkByInfo(string dest, string src)
{
    var info = new DirectoryInfo(dest).Dump("Create");
    info.CreateAsSymbolicLink(src);
}

void DeleteSymlink(string path)
{
    Directory.Delete(path);
}
void Resolve(string path, bool finalTarget)
{
    Directory.ResolveLinkTarget(path, finalTarget).Dump("Resolve");
}
void ResolveByInfo(string path, bool finalTarget)
{
    var info = new DirectoryInfo(path);
    info.ResolveLinkTarget(finalTarget).Dump("Resolve");
}
void GetSymLinkList(string root)
{
    var dirs = Directory.EnumerateDirectories(root, "*", SearchOption.AllDirectories);
    dirs.Select(path => new DirectoryInfo(path))
        .Select(info => new { Path = info.FullName, Symlink = info.LinkTarget != null, Link = info.LinkTarget })
        .Dump("LinkList");
}