LongPathException问题解析


一、背景
      当windows系统下使用System.IO命名空间下的方法,目录长度超过260个字符时,.net framework会抛出LongPathException。查阅相关资料,发现是微软为了安全和系统兼容性做出的限制。
      原话是这么说的:The exception that is thrown when a path or file name is longer than the system-defined maximum length.
      关于这个问题更详细的说明在这里:http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
      当然有过人已经中文翻译过来了: http://www.cnblogs.com/tongling/archive/2007/04/26/728224.html

      LongPathException详细:http://msdn.microsoft.com/en-us/library/System.IO.PathTooLongException(v=vs.110).aspx
      

      

二、解决方案

方法一:用官方说的方法,用unicode的编码方式调用win32 API,并且在路径前面加前缀:\\?\。

这个链接是官方提供的解决办法: http://msdn.microsoft.com/en-us/library/930f87yf(vs.80).aspx
下面是包装了CreateDirectory和CreateFile。经过测试,可以正常使用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.IO;

namespace STAr.Aquarius.Infrastructure.Library
{
    public static class LongPathHelper
    {
        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.Unicode, 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 SafeFileHandle CreateFile(string path)
        {
            SafeFileHandle handle = Win32Native.CreateFile(String.Concat(@"\\?\", path), (int)0x10000000, FileShare.None, null, FileMode.CreateNew, (int)0x00000080, IntPtr.Zero);
            if (handle.IsInvalid)
            {
                throw new System.ComponentModel.Win32Exception();
            }
            return handle;
        }
        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);
        }

    }
}

 

其他使用到的API,自己在按照上面的方法包装即可。这种方法可以解决问题,就是太麻烦,因为所有用到的都需要自己动手包装,费力不讨好不说,PInvoke的调用写起来也比较麻烦,不知道大家有没有一种好的办法,可以高效的解决这个问题。
我只知道有一个pinvoke.net的网站上可以查询相关API的写法。有更好的方法,记得告诉我哦。

方法二、用第三方开源类库:alphafs
官方地址:http://alphafs.codeplex.com/
这个alphafs是对System.IO.FileStream的完整包装,几乎支持所有的System.IO.File,System.IO.Directory.System.IO.FileStream...

原话:AlphaFS is a .NET library providing more complete Win32 file system functionality to the .NET platform than the standard System.IO classes. 
,还有一个好处是,他的方法名和System.IO完全一样。那我们改起来只需要修改引用不就可以了吗。
下面写的测试程序,经测,可以使用:(ps需要引用AlphaFS.dll这个dll.)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Alphaleonis.Win32.Filesystem;

namespace LongPath
{
    /// <summary>
    /// http://stackoverflow.com/questions/12747132/pathtoolongexception-c-sharp-4-5
    /// http://msdn.microsoft.com/en-us/library/930f87yf(vs.80).aspx
    /// https://zetalongpaths.codeplex.com/
    /// http://alphafs.codeplex.com/
    /// Author:http://www.cnblogs.com/deepleo/
    /// Email:2586662969@qq.com
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            var path = @"\\?\C:\Issues\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\20140710\ProblemOvernight\Data\[20140812_162155_][20140812_162155][20140812_162155][20140812_162155]\[20140812_162155_][20140812_162155][20140812_162155][20140812_162155]";
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            Console.WriteLine("Path's Length is {0}", path.Length);
            var newDir = string.Concat(path, @"\" + Guid.NewGuid().ToString());
            Directory.CreateDirectory(newDir);
            Console.WriteLine("New dir is created {0}", Directory.Exists(newDir));
            var newFile = Path.Combine(newDir, Guid.NewGuid().ToString());
            File.Create(newFile);
            Console.WriteLine("New file is created {0}", File.Exists(newFile));
            Console.ReadKey();
        }
    }
}

 

当然,最好的解决办法是,你能说服你的客户,不改,让他不要把路径搞那么长,算你牛逼!!!

下面附上完整测试程序源代码:http://files.cnblogs.com/deepleo/LongPath.rar

alphafs可以到官方网站上下载,也可以在我这里下载:http://files.cnblogs.com/deepleo/AlphaFS.rar

posted @ 2014-08-22 14:39 夜の魔王 阅读(...) 评论(...) 编辑 收藏