Windows OS PathTooLongException 转摘自http://www.cstruter.com/blog/308

When I told one of my developer friends that I am going to write a post about the PathTooLongException, he found it rather amusing - how much could there really be to this Exception? 

In Windows the full path of a file/folder can't be longer than 260 characters, this limit is enforced by the .net framework and normally by the operating system as well (one can't create a full path longer than 260 characters via windows explorer for example)

But recently however, I noticed a more interesting issue surrounding this exception while importing folders/files using a tool I wrote - quite a number of the paths exceeded the 260 character limit and obviously raised the PathTooLongException when the code attempted to import the folders/files. 

Which obviously means that this limit can't exactly be set in stone. 

After doing some digging (and playing around), I found its possible to circumvent the 260 limit programatically(Win32 API - Unicode via the "\\?\" prefix) and using 8.3 path names via the Windows console as well (upto aprox 32000 characters)

In the following snippet we succeed in creating paths longer than 260 characters via 8.3 file/folder names: 

 
c:
cd\
md aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaa~1
md aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
cd aaaaaa~1
dir c:\ > test.txt
 


The interesting thing (after running this snippet) on Windows XP/2003, is that one can't even browse to the file within the second folder - but on Windows 7/2008 (and I would imagine Vista as well) it was possible to browse to that file at least. 

Now if we try to delete the folder (created via the previous snippet) using windows explorer, windows will swear at us (whoops you've just created a folder you can't remove, bwahaha)

Just joking, you will be able to remove those folders using the following snippet: 

 
c:
cd\aaaaaa~1\aaaaaa~1
del test.txt
cd..
rd aaaaaa~1
cd..
rd aaaaaa~1
 


As for the second way (that I know of) to sidestep the 260 character limit, can be seen in the following extremely crude snippet (don't use as is) - via the Win32 API. 

 
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
 
public static class LongPath
{
    static class Win32Native
    {
        [StructLayout(LayoutKind.Sequential)]
        public class SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr pSecurityDescriptor;
            public int bInheritHandle;
        }
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CreateDirectory(string lpPathName, SECURITY_ATTRIBUTES lpSecurityAttributes);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
    }
 
    public static bool CreateDirectory(string path)
    {
        return Win32Native.CreateDirectory(String.Concat(@"\\?\", path), null);
    }
 
    public static FileStream Open(string path, FileMode mode, FileAccess access)
    {
        SafeFileHandle handle = Win32Native.CreateFile(String.Concat(@"\\?\", path), (int)0x10000000, FileShare.None, null, mode, (int)0x00000080, IntPtr.Zero);
        if (handle.IsInvalid)
        {
            throw new System.ComponentModel.Win32Exception();
        }
        return new FileStream(handle, access);
    }
}
 


The interesting thing to note here, is that each segment created like this can't be longer than 255 characters(which is a bit longer than the folder names we can create via the 8.3 method) e.g. "c:\<255>\<255>\<255.ext>". 

In the next snippet we apply the LongPath class as seen in the preceding snippet, which demonstrates how to access these files programmatically. 

 
string path = @"c:\".PadRight(255, 'a');
LongPath.CreateDirectory(path);
 
path = String.Concat(path, @"\", "".PadRight(255, 'a'));
LongPath.CreateDirectory(path);
 
string filename = Path.Combine(path, "test.txt");
 
FileStream fs = LongPath.Open(filename, FileMode.CreateNew, FileAccess.Write);
 
using (StreamWriter sw = new StreamWriter(fs))
{
    sw.WriteLine("abc");
}
 


Another interesting thing to note, is that one can't browse to the folders created in the preceding snippet, in any of the Windows Operating systems - it is however still possible to access them via the windows console using 8.3 file/folder names. 

All of this is a bit of an ugly situation, infact most of the apps I tested didn't support reading/importing files affected by this issue. Is this an issue we must simply ignore? 

Additional Reading
http://www.hanno.co.za/post/2011/04/04/Copying-files-with-very-long-filenames-paths.aspxhttp://msdn.microsoft.com/en-us/library/aa365247.aspx
http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
http://vlaurie.com/computers2/Articles/filenames.htm

posted @ 2014-12-16 14:24  PrettyISShit  阅读(297)  评论(0编辑  收藏  举报