Gal Ratner
Gal Ratner is a Techie who lives and works in Los Angeles CA and Austin TX. Follow galratner on Twitter Google
Getting around PathTooLongException on file move with Windows Native API

If you ever got the error message “The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters. “ you are probably aware that there is no practical way of moving files with long paths using System.IO.File. The solution is to use the Native Windows API. You can see the API here: http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx
Here is a little helper class I wrote to utilize the native API from .NET:

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace InvertedSoftware.IO
{
[Flags]
public 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
}

/// <summary>
/// A class for file IO using the native windows API
/// </summary>
public static class FileIONative
{
/// <summary>
/// Delete a file using the native Windows API
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static bool Delete(string fileName)
{
string formattedName = @"\\?\" + fileName;
if (!DeleteFile(formattedName))
throw new Win32Exception();
return true;
}

/// <summary>
/// Move a file using the native Windows API
/// </summary>
/// <param name="fromFileName"></param>
/// <param name="toFileName"></param>
/// <returns></returns>
public static bool Move(string fromFileName, string toFileName)
{
string formattedfromFileName = @"\\?\" + fromFileName;
string formattedtoFileName = @"\\?\" + toFileName;
if (!MoveFile(formattedfromFileName, formattedtoFileName))
throw new Win32Exception();
return true;
}

public static bool MoveEx(string fromFileName, string toFileName)
{
string formattedfromFileName = @"\\?\" + fromFileName;
string formattedtoFileName = @"\\?\" + toFileName;
if (!MoveFileEx(formattedfromFileName, formattedtoFileName, MoveFileFlags.MOVEFILE_REPLACE_EXISTING | MoveFileFlags.MOVEFILE_COPY_ALLOWED))
throw new Win32Exception();
return true;
}

/// <summary>
/// Copy a file using the native Windows API
/// </summary>
/// <param name="fromFileName"></param>
/// <param name="toFileName"></param>
/// <param name="overrideExisting"></param>
/// <returns></returns>
public static bool Copy(string fromFileName, string toFileName, bool overrideExisting)
{
string formattedfromFileName = @"\\?\" + fromFileName;
string formattedtoFileName = @"\\?\" + toFileName;
if (!CopyFile(formattedfromFileName, formattedtoFileName, overrideExisting))
throw new Win32Exception();
return true;
}

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[returnMarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteFile(string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[returnMarshalAs(UnmanagedType.Bool)]
internal static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[returnMarshalAs(UnmanagedType.Bool)]
internal static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[returnMarshalAs(UnmanagedType.Bool)]
internal static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);
}
}

Usage looks like:

FileIONative.Copy(FileName, destinationFileName, overrideExisting);


Any errors will throw a Win32Exception.

 

UPDATE: You can now prepend "\\?\" to your path in order by pass the .NET maximum path length.

For example: "\\?\D:\very long path".

* .NET Framework 4.6.2 has removed this limitation altogether.

Shout it


Posted 13 Feb 2011 7:57 AM by Gal Ratner
Filed under: ,

Powered by Community Server (Non-Commercial Edition), by Telligent Systems