As, @helge-klein pointed out there is no .Net API to work around the limitation of 260 characters, that feature is totally OS dependant, some of which support a Registry based override of the 260 max_path limitation.
[Edit] DotNet 4.6.2 onwards support: System.IO.LongPath, Blog and sample
Windows 10 Creators Update has extended the kernel (and command prompt) to have MoveFileExW, but as is evident in the dotnetReferenceSource no use of the extended kernel is included in the 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
An example LinqPad program to wrap MoveFile (others can be found on 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);
Paths with a drive and UNC path need the keyword "UNC". \?\UNC\
Path.Combine(@"\\?\", path)
returnspath
, whenpath
is rooted. I've edited the example to be more correct. – Petromilli