C# 如何避免 System.IO.PathTooLongException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/530109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to avoid System.IO.PathTooLongException?
提问by theKing
We constantly run into this problem...
我们经常遇到这个问题......
Example:
例子:
if I have a file that I want to copy it into an another directory or UNC share and if the length of the path exceeds 248 (if I am not mistaken), then it throws PathTooLongException. Is there any workaround to this problem?
如果我有一个文件想要将其复制到另一个目录或 UNC 共享中,并且路径的长度超过 248(如果我没有记错的话),那么它会抛出 PathTooLongException。这个问题有什么解决方法吗?
PS: Is there any registry setting to set this path to a longer char set?
PS:是否有任何注册表设置可以将此路径设置为更长的字符集?
采纳答案by Mark Hurd
回答by Brandon
Only 1 workaround that I've seen on this one... this might be helpful
我在这个上看到的只有一种解决方法......这可能会有所帮助
回答by ShuggyCoUk
This has been discussed in depth by the BCL team, see the blog entries
BCL 团队对此进行了深入讨论,请参阅博客条目
In essence there is no way to do this within .Net codeand stick to the BCL. Too many functions rely on being able to canonicalize the path name (which immediately triggers the use of functions expecting MAX_PATH to be obeyed).
本质上,没有办法在 .Net 代码中做到这一点并坚持 BCL。太多的函数依赖于能够规范化路径名(这会立即触发期望遵守 MAX_PATH 的函数的使用)。
You could wrap all the win32 functions that support the "\\?\" syntax, with these you would be able to implement a suite of long path aware functionality but this would be cumbersome.
您可以包装所有支持“\\?\”语法的 win32 函数,通过这些函数,您将能够实现一套长路径感知功能,但这会很麻烦。
Since a vast number of tools (including explorer[1]) cannot handle long path names it is inadvisable to go down this route unless you are happy that allinteraction with the resulting file system goes through your library (or the limited number of tools that are built to handle it like robocopy)
由于大量工具(包括资源管理器 [1])无法处理长路径名,因此不建议沿着这条路线走下去,除非您很高兴与生成的文件系统的所有交互都通过您的库(或有限数量的工具)旨在像 robocopy 一样处理它)
In answer to your specific need I would investigate whether the use of robocopy directly would be sufficient to perform this task.
为了满足您的特定需求,我将调查直接使用 robocopy 是否足以执行此任务。
[1] Vista has ways to mitigate the issue with some fancy renaming under the hood but this is fragile at best)
[1] Vista 有办法通过一些花哨的重命名来缓解这个问题,但这充其量是脆弱的)
回答by Jason S
The problem is with the ANSI versions of the Windows APIs. One solution that needs to be tested carefully is to force the use of Unicode versions of the Windows API. This can be done by prepending "\\?\
" to the path being queried.
问题在于 Windows API 的 ANSI 版本。需要仔细测试的一种解决方案是强制使用 Unicode 版本的 Windows API。这可以通过\\?\
在要查询的路径前加上“ ”来完成。
Great information, including work arounds can be found in the following blog posts from Microsoft's Base Class Library (BCL) Team titled "Long Paths in .NET":
可以在以下来自 Microsoft 基类库 (BCL) 团队的名为“.NET 中的长路径”的博客文章中找到包括变通方法在内的重要信息:
- http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
- http://blogs.msdn.com/bclteam/archive/2007/03/26/long-paths-in-net-part-2-of-3-long-path-workarounds-kim-hamilton.aspx
- http://blogs.msdn.com/b/bclteam/archive/2008/07/07/long-paths-in-net-part-3-of-3-redux-kim-hamilton.aspx
- http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
- http://blogs.msdn.com/bclteam/archive/2007/03/26/long-paths-in-net-part-2-of-3-long-path-workarounds-kim-hamilton.aspx
- http://blogs.msdn.com/b/bclteam/archive/2008/07/07/long-paths-in-net-part-3-of-3-redux-kim-hamilton.aspx
回答by A. Harald
I used the "subst" command to work around the problem... http://www.techrepublic.com/article/mapping-drive-letters-to-local-folders-in-windows-xp/5975262
我使用“subst”命令来解决这个问题...... http://www.techrepublic.com/article/mapping-drive-letters-to-local-folders-in-windows-xp/5975262
回答by CodingYourLife
In C# for me this is a workaround:
在 C# 中,对我来说这是一种解决方法:
/*make long path short by setting it to like cd*/
string path = @"\godDamnLong\Path\";
Directory.SetCurrentDirectory(path);
回答by JeffRSon
This library might be helpful: Zeta Long Paths
这个库可能会有所帮助: Zeta Long Paths
回答by Elshan
Try This : Delimon.Win32.I?O Library (V4.0)This Libarary is written on .NET Framework 4.0
试试这个:Delimon.Win32.I?O 库 (V4.0)这个库是在 .NET Framework 4.0 上编写的
Delimon.Win32.IO replaces basic file functions of System.IO and supports File & Folder names up to up to 32,767Characters.
Delimon.Win32.IO 取代了 System.IO 的基本文件功能,支持最多32,767 个字符的文件和文件夹名称。
https://gallery.technet.microsoft.com/DelimonWin32IO-Library-V40-7ff6b16c
https://gallery.technet.microsoft.com/DelimonWin32IO-Library-V40-7ff6b16c
This Library is written specifically to overcome the limitation of the .NET Framework to use long Path & File Names. With this Library you can programmatically browse, access, write, delete, etc Files and Folders that are not accessible by the System.IO namespace.Library
该库是专门为克服 .NET Framework 使用长路径和文件名的限制而编写的。使用此库,您可以以编程方式浏览、访问、写入、删除等 System.IO 命名空间无法访问的文件和文件夹。
Usage
用法
First add a reference to the Delimon.Win32.IO.dll to your project (Browse to the Delimon.Win32.IO.dll file)
In your Code File add "using Delimon.Win32.IO"
Use normal File & Directory Objects as if you are working with System.IO
首先在您的项目中添加对 Delimon.Win32.IO.dll 的引用(浏览至 Delimon.Win32.IO.dll 文件)
在您的代码文件中添加“使用 Delimon.Win32.IO”
像使用 System.IO 一样使用普通的文件和目录对象
回答by alex
My Drive-Mapping solution works fine and stable using ?NetWorkDrive.cs“ and ?NetWorkUNCPath.cs“ which are listed below.
我的 Drive-Mapping 解决方案使用下面列出的“NetWorkDrive.cs”和“NetWorkUNCPath.cs”运行良好且稳定。
Test example:
测试示例:
if (srcFileName.Length > 260)
{
string directoryName = srcFileName.Substring(0, srcFileName.LastIndexOf('\'));
var uncName = GetUNCPath(srcFileName.Substring(0, 2)) + directoryName.Substring(2);
using (NetWorkDrive nDrive = new NetWorkDrive(uncName))
{
drvFileName = nDrive.FullDriveLetter + Path.GetFileName(sourceFileName)
File.Copy(drvFileName, destinationFileName, true);
}
}
else
{
File.Copy(srcFileName, destinationFileName, true);
}
NetWorkDrive.cssouce code:
NetWorkDrive.cs源代码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace SeekCopySupportTool.Business
{
public class NetWorkDrive : IDisposable
{
#region private fields
private string m_DriveLetter = string.Empty;
private string m_FullDriveLetter = string.Empty;
private bool m_Disposed = false;
//this list specifies the drive-letters, whitch will be used to map networkfolders
private string[] possibleDriveLetters = new string[]
{
"G:\",
"H:\",
"I:\",
"J:\",
"K:\",
"L:\",
"M:\",
"N:\",
"O:\",
"P:\",
"Q:\",
"R:\",
"S:\",
"T:\",
"U:\",
"V:\",
"W:\",
"X:\",
"Y:\",
"Z:\"
};
#endregion
#region public properties
public string DriveLetter
{
get { return m_DriveLetter; }
set { m_DriveLetter = value; }
}
public string FullDriveLetter
{
get { return m_FullDriveLetter; }
set { m_FullDriveLetter = value; }
}
#endregion
#region .ctor
public NetWorkDrive(string folderPath)
{
m_FullDriveLetter = MapFolderAsNetworkDrive(folderPath);
if (string.IsNullOrEmpty(m_FullDriveLetter))
{
throw new Exception("no free valid drive-letter found");
}
m_DriveLetter = m_FullDriveLetter.Substring(0,2);
}
#endregion
#region private methods
/// maps a given folder to a free drive-letter (f:\)
/// <param name="folderPath">the folder to map</param>
/// <returns>the drive letter in this format: "(letter):\" -> "f:\"</returns>
/// <exception cref="Win32Exception">if the connect returns an error</exception>
private string MapFolderAsNetworkDrive(string folderPath)
{
string result = GetFreeDriveLetter();
NETRESOURCE myNetResource = new NETRESOURCE();
myNetResource.dwScope = ResourceScope.RESOURCE_GLOBALNET;
myNetResource.dwType = ResourceType.RESOURCETYPE_ANY;
myNetResource.dwDisplayType = ResourceDisplayType.RESOURCEDISPLAYTYPE_SERVER;
myNetResource.dwUsage = ResourceUsage.RESOURCEUSAGE_CONNECTABLE;
myNetResource.lpLocalName = result.Substring(0,2);
myNetResource.lpRemoteName = folderPath;
myNetResource.lpProvider = null;
int errorcode = WNetAddConnection2(myNetResource, null, null, 0);
if(errorcode != 0)
{
throw new Win32Exception(errorcode);
}
return result;
}
private void DisconnectNetworkDrive()
{
int CONNECT_UPDATE_PROFILE = 0x1;
int errorcode = WNetCancelConnection2(m_DriveLetter, CONNECT_UPDATE_PROFILE, true);
if (errorcode != 0)
{
throw new Win32Exception(errorcode);
}
}
private string GetFreeDriveLetter()
{
//first get the existing driveletters
const int size = 512;
char[] buffer = new char[size];
uint code = GetLogicalDriveStrings(size, buffer);
if (code == 0)
{
return "";
}
List<string> list = new List<string>();
int start = 0;
for (int i = 0; i < code; ++i)
{
if (buffer[i] == 0)
{
string s = new string(buffer, start, i - start);
list.Add(s);
start = i + 1;
}
}
foreach (string s in possibleDriveLetters)
{
if (!list.Contains(s))
{
return s;
}
}
return null;
}
#endregion
#region dll imports
/// <summary>
/// to connect to a networksource
/// </summary>
/// <param name="netResource"></param>
/// <param name="password">null the function uses the current default password associated with the user specified by the username parameter ("" the function does not use a password)</param>
/// <param name="username">null the function uses the default user name (The user context for the process provides the default user name)</param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport("mpr.dll")]
//public static extern int WNetAddConnection2(ref NETRESOURCE netResource, string password, string username, int flags);
private static extern int WNetAddConnection2([In] NETRESOURCE netResource, string password, string username, int flags);
/// <summary>
/// to disconnect the networksource
/// </summary>
/// <param name="lpName"></param>
/// <param name="dwFlags"></param>
/// <param name="bForce"></param>
/// <returns></returns>
[DllImport("mpr.dll")]
private static extern int WNetCancelConnection2(string lpName, Int32 dwFlags, bool bForce);
/// <param name="nBufferLength"></param>
/// <param name="lpBuffer"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
private static extern uint GetLogicalDriveStrings(uint nBufferLength, [Out] char[] lpBuffer);
#endregion
#region enums/structs
/// <example>
/// NETRESOURCE myNetResource = new NETRESOURCE();
/// myNetResource.dwScope = 2;
/// myNetResource.dwType = 1;
/// myNetResource.dwDisplayType = 3;
/// myNetResource.dwUsage = 1;
/// myNetResource.LocalName = "z:";
/// myNetResource.RemoteName = @"\servername\sharename";
/// myNetResource.Provider = null;
/// </example>
[StructLayout(LayoutKind.Sequential)]
public class NETRESOURCE
{
public ResourceScope dwScope = 0;
public ResourceType dwType = 0;
public ResourceDisplayType dwDisplayType = 0;
public ResourceUsage dwUsage = 0;
public string lpLocalName = null;
public string lpRemoteName = null;
public string lpComment = null;
public string lpProvider = null;
};
public enum ResourceScope : int
{
RESOURCE_CONNECTED = 1,
RESOURCE_GLOBALNET,
RESOURCE_REMEMBERED,
RESOURCE_RECENT,
RESOURCE_CONTEXT
};
public enum ResourceType : int
{
RESOURCETYPE_ANY,
RESOURCETYPE_DISK,
RESOURCETYPE_PRINT,
RESOURCETYPE_RESERVED
};
public enum ResourceUsage
{
RESOURCEUSAGE_CONNECTABLE = 0x00000001,
RESOURCEUSAGE_CONTAINER = 0x00000002,
RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
RESOURCEUSAGE_SIBLING = 0x00000008,
RESOURCEUSAGE_ATTACHED = 0x00000010,
RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
};
public enum ResourceDisplayType
{
RESOURCEDISPLAYTYPE_GENERIC,
RESOURCEDISPLAYTYPE_DOMAIN,
RESOURCEDISPLAYTYPE_SERVER,
RESOURCEDISPLAYTYPE_SHARE,
RESOURCEDISPLAYTYPE_FILE,
RESOURCEDISPLAYTYPE_GROUP,
RESOURCEDISPLAYTYPE_NETWORK,
RESOURCEDISPLAYTYPE_ROOT,
RESOURCEDISPLAYTYPE_SHAREADMIN,
RESOURCEDISPLAYTYPE_DIRECTORY,
RESOURCEDISPLAYTYPE_TREE,
RESOURCEDISPLAYTYPE_NDSCONTAINER
};
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
}
#endregion
#region overrides/virtuals
public override string ToString()
{
return m_FullDriveLetter;
}
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!m_Disposed)
{
if (disposing)
{
DisconnectNetworkDrive();
}
m_Disposed = true;
}
}
#endregion
}
}
NetWorkUNCPath.cssource code:
NetWorkUNCPath.cs源代码:
using System;
using System.Management;
namespace SeekCopySupportTool.Business
{
public class NetWorkUNCPath
{
// get UNC path
public static string GetUNCPath(string path)
{
if (path.StartsWith(@"\"))
{
return path;
}
ManagementObject mo = new ManagementObject();
mo.Path = new ManagementPath(String.Format("Win32_LogicalDisk='{0}'", path));
// DriveType 4 = Network Drive
if (Convert.ToUInt32(mo["DriveType"]) == 4)
{
return Convert.ToString(mo["ProviderName"]);
}
// DriveType 3 = Local Drive
else if (Convert.ToUInt32(mo["DriveType"]) == 3)
{
return "\\" + Environment.MachineName + "\" + path.Substring(0,1) + "$";
}
else
{
return path;
}
}
}
}