是否有.NET API来返回给定路径的等效扩展路径字符串?

时间:2011-07-29 00:45:50

标签: ntfs .net path-combine

在NTFS中,我可以在路径前加上\\?\字符序列,以表示它是超过260个字符限制的路径;因此,文件系统将正确解释路径并避免引发PathTooLongException

(有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx#maxpath

是否有一个.NET API会在我的路径字符串前面加上这个序列,或者我是不是自己写了?

本质上,我正在寻找一种与以下相同的方法。

static string ToExtendedPath(string path)
{
    if(Path.IsPathRooted(path))
    {
        return @"\\?\" + path;
    }

    return Path.Combine(@"\\?\", path);
}

2 个答案:

答案 0 :(得分:6)

不,没有.NET API将给定的“普通”路径转换为扩展语法。你必须自己动手(顺便说一句,这是微不足道的。)

请注意:正如Cody Gray和Hans Passant所提到的,.NET框架不支持长(扩展)路径。如果您想使用它们,则需要直接使用API​​。并非所有API函数都支持长路径。通常,低级函数可以。请参阅MSDN文档。

我所做的是为相关API函数(例如CreateFile)编写包装函数,并调用那些包装器而不是.NET文件系统函数。

答案 1 :(得分:0)

as,@ helge-klein指出没有.Net API可以解决260个字符的限制,该功能完全取决于操作系统,其中一些支持Registry based override of the 260 max_path limitation

[编辑] DotNet 4.6.2以上支持:System.IO.LongPathBlog and sample

Windows 10 Creators Update已将内核(和命令提示符)扩展为MoveFileEx W ,但正如dotnetReferenceSource中明显的那样,DotNet中不包含扩展内核的使用Framework System.IO.File:

#if FEATURE_CORESYSTEM
    [DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
    [ResourceExposure(ResourceScope.Machine)]
    private static extern bool MoveFileEx(String src, String dst, uint flags);

    internal static bool MoveFile(String src, String dst)
    {
        return MoveFileEx(src, dst, 2 /* MOVEFILE_COPY_ALLOWED */);
    }
#else // FEATURE_CORESYSTEM
    [DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
    [ResourceExposure(ResourceScope.Machine)]
    internal static extern bool MoveFile(String src, String dst);
#endif // FEATURE_CORESYSTEM

用于包装MoveFile的示例LinqPad程序(其他可以在pinvoke上找到)

void Main()
{
    //Create 3 files: in c:\temp\test\
    //testsrc0.txt, testsrc1.txt and testsrc2.txt
    //"\\?\UNC\server\share", 
    string src0File = @"\\?\UNC\127.0.0.1\c$\temp\test\testsrc0.txt";
    string dst0File = @"\\?\UNC\127.0.0.1\c$\temp\test\testdst0.txt";
    string dst0FileDotNet = @"c:\temp\test\testdst0.txt";
    string src1File = @"\\?\c:\temp\test\testsrc1.txt";
    string dst1File = @"\\?\c:\temp\test\testdst1.txt";
    string dst1FileDotNet = @"c:\temp\test\testdst1.txt";
    string src2File = @"\\?\\127.0.0.1\c$\temp\test\testsrc2.txt";
    string dst2File = @"\\?\\127.0.0.1\c$\temp\test\testdst2.txt";
    string dst2FileDotNet = @"c:\temp\test\testdst2.txt";

    MoveFileEx(src0File, dst0File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
    System.IO.File.Exists(dst0File).Dump("File0 Exists");//FALSE
    System.IO.File.Exists(dst0FileDotNet).Dump("File0 Exists");//TRUE    

    MoveFileEx(src1File, dst1File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
    System.IO.File.Exists(dst1File).Dump("File1 Exists");//FALSE
    System.IO.File.Exists(dst1FileDotNet).Dump("File1 Exists");//TRUE    

    MoveFileEx(src2File, dst2File, MoveFileFlags.MOVEFILE_REPLACE_EXISTING);
    System.IO.File.Exists(dst2File).Dump("File2 Exists");//FALSE
    System.IO.File.Exists(dst2FileDotNet).Dump("File2 Exists");//FALSE - as missing UNC keyword
    System.Runtime.InteropServices.Marshal.GetLastWin32Error().Dump("ERROR:");//3 == ERROR_PATH_NOT_FOUND
}

[Flags]
enum MoveFileFlags
{
    MOVEFILE_REPLACE_EXISTING = 0x00000001,
    MOVEFILE_COPY_ALLOWED = 0x00000002,
    MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,
    MOVEFILE_WRITE_THROUGH = 0x00000008,
    MOVEFILE_CREATE_HARDLINK = 0x00000010,
    MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}

// Define other methods and classes here
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);

带有驱动器和UNC路径的路径需要关键字“UNC”。 \?\ UNC \