Thursday, December 26, 2013

Exception : Path is too long - RESOLVED


While working on a problem today, we were getting following exception. I agree that we were using very long path but we can't do anything with folder structure. It was a client share.

Exception:

The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

   at System.IO.Path.SafeSetStackPointerValue(Char* buffer, Int32 index, Char value)
   at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)
   at System.IO.Path.NormalizePath(String path, Boolean fullCheck)
   at System.IO.Path.GetFullPathInternal(String path)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
     at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()


After searching on internet, I came to know that standard .NET API doesn't support that. Hence we moved  back to COM or WinAPI era i.e. full power to play with system. One of the API that suit our requirement is : 
CopyFile

This is how we fixed our issue:

1. Copy respective file using above API to a temporary location.
2. Performed required operations.
3. Delete file from temporary location.

As we have a .NET based application, following is the way to use this API:

Step 1:

Declare P/I invoke statement

 [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]

        static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);

where 

lpNewFileName - New path including file name.

lpExistingFileName - is a LONG file path including file name.  It can be of two types:

long path is always prefixed with : "\\?\"  when using above API.

a) In case of local drive:  \\?\D:\very long path

b) In case of network drive:

"\\?\" prefix is used with paths constructed according to the universal naming convention (UNC). To specify such a path using UNC, use the "\\?\UNC\" prefix. For example, "\\?\UNC\server\share", where "server" is the name of the computer and "share" is the name of the shared folder. These prefixes are not used as part of the path itself. They indicate that the path should be passed to the system with minimal modification, which means that you cannot use forward slashes to represent path separators, or a period to represent the current directory, or double dots to represent the parent directory. Because you cannot use the "\\?\" prefix with a relative path, relative paths are always limited to a total of MAX_PATH characters.

Example:
\\?\UNC\serverXYZ\Myfoldershare\very long path

Step 2:

Call above API as normal method.

 CopyFile(reallyLongPath, destination, false);

That's it.  File will copy to your destination path. Now, you can play as needed.

Note
Many but not all file I/O APIs support "\\?\"; you should look at the reference topic for each API to be sure.