在 .NET 4.7 中使用长路径时出现 DirectoryNotFoundException
DirectoryNotFoundException when using long paths in .NET 4.7
我已将本地组策略编辑器中的Enable Win32 Long Paths
设置为Enabled
并重新启动计算机。
这是代码:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
for (int i = 0; i < 10; i++)
path += "\" + new string('z', 200);
Directory.CreateDirectory(path);
我遇到错误:
System.IO.DirectoryNotFoundException: 'Could not find a part of the
path 'C:\Users...\Desktop\zzzzzzzzzz...
(这实际上是一个奇怪的错误信息。)
app.config 已经有:
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
更多信息(可能不重要)
我尝试在 configuration
下的 app.config 中添加 this post 和其他地方提到的(尽管在评论中指出使用 .net 4.7 时不需要):
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>
还是一样的错误。
如果我只使用一个 zzzzzz...
它会在桌面上创建它而没有错误。
我用的是VS2017,Windows10.我试过Winforms和WPF
这可能无法回答您的问题,但会为您提供解决方法的提示。我在 Ubuntu Linux 下用 mono 4.5 测试了你的代码片段,效果很好,但在 Windows 中,情况可能有点不同。这里,怪罪的似乎是.NET Framework 本身,关于this article and this other article,不支持长路径。
因此,@Anastasiosyal 在 this Whosebug answer 中建议的解决方案是依赖 Windows Api 本身。有两种方式:直接绕过或者Api调用
Directory.CreateDirectory(@"\?\" + veryLongPath);
Api 调用(代码不是我的,是从@Anastasiosyal 的回答中得到的):
// This code snippet is provided under the Microsoft Permissive License.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
public static void TestCreateAndWrite(string fileName) {
string formattedName = @"\?\" + fileName;
// Create a file with generic write access
SafeFileHandle fileHandle = CreateFile(formattedName,
EFileAccess.GenericWrite, EFileShare.None, IntPtr.Zero,
ECreationDisposition.CreateAlways, 0, IntPtr.Zero);
// Check for errors
int lastWin32Error = Marshal.GetLastWin32Error();
if (fileHandle.IsInvalid) {
throw new System.ComponentModel.Win32Exception(lastWin32Error);
}
// Pass the file handle to FileStream. FileStream will close the
// handle
using (FileStream fs = new FileStream(fileHandle,
FileAccess.Write)) {
fs.WriteByte(80);
fs.WriteByte(81);
fs.WriteByte(83);
fs.WriteByte(84);
}
}
此外,我建议您使用 Path.Combine
而不是 path + "\" + subpath
。
周年更新 (RS1) 有一个错误,允许长路径在没有清单的情况下工作。对于任何更新的 Windows,您必须将应用程序清单文件项添加到您的项目中。不然不行。
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
我有一个经验:
1) 在桌面应用程序 (.NET 4.7) 中,您不再需要其他任何东西,然后使用带有前缀 @"\?\ 的路径名(不需要清单,在 app.confing 中设置 UseLegacyPathHandling)和所有作品
2) 在 web 应用程序中你必须这样设置:
bool legacyPaths;
if (AppContext.TryGetSwitch("Switch.System.IO.UseLegacyPathHandling", out legacyPaths) && legacyPaths)
{
var switchType = Type.GetType("System.AppContextSwitches");
if (switchType != null)
{
AppContext.SetSwitch("Switch.System.IO.UseLegacyPathHandling", false);
var legacyField = switchType.GetField("_useLegacyPathHandling", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
legacyField?.SetValue(null, (Int32)0);
AppContext.TryGetSwitch("Switch.System.IO.UseLegacyPathHandling", out legacyPaths);
Assert.IsFalse(legacyPaths, "Long pathnames are not supported!");
}
}
希望对你有所帮助!
我已将本地组策略编辑器中的Enable Win32 Long Paths
设置为Enabled
并重新启动计算机。
这是代码:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
for (int i = 0; i < 10; i++)
path += "\" + new string('z', 200);
Directory.CreateDirectory(path);
我遇到错误:
System.IO.DirectoryNotFoundException: 'Could not find a part of the path 'C:\Users...\Desktop\zzzzzzzzzz...
(这实际上是一个奇怪的错误信息。)
app.config 已经有:
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
更多信息(可能不重要)
我尝试在 configuration
下的 app.config 中添加 this post 和其他地方提到的(尽管在评论中指出使用 .net 4.7 时不需要):
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>
还是一样的错误。
如果我只使用一个 zzzzzz...
它会在桌面上创建它而没有错误。
我用的是VS2017,Windows10.我试过Winforms和WPF
这可能无法回答您的问题,但会为您提供解决方法的提示。我在 Ubuntu Linux 下用 mono 4.5 测试了你的代码片段,效果很好,但在 Windows 中,情况可能有点不同。这里,怪罪的似乎是.NET Framework 本身,关于this article and this other article,不支持长路径。
因此,@Anastasiosyal 在 this Whosebug answer 中建议的解决方案是依赖 Windows Api 本身。有两种方式:直接绕过或者Api调用
Directory.CreateDirectory(@"\?\" + veryLongPath);
Api 调用(代码不是我的,是从@Anastasiosyal 的回答中得到的):
// This code snippet is provided under the Microsoft Permissive License.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
public static void TestCreateAndWrite(string fileName) {
string formattedName = @"\?\" + fileName;
// Create a file with generic write access
SafeFileHandle fileHandle = CreateFile(formattedName,
EFileAccess.GenericWrite, EFileShare.None, IntPtr.Zero,
ECreationDisposition.CreateAlways, 0, IntPtr.Zero);
// Check for errors
int lastWin32Error = Marshal.GetLastWin32Error();
if (fileHandle.IsInvalid) {
throw new System.ComponentModel.Win32Exception(lastWin32Error);
}
// Pass the file handle to FileStream. FileStream will close the
// handle
using (FileStream fs = new FileStream(fileHandle,
FileAccess.Write)) {
fs.WriteByte(80);
fs.WriteByte(81);
fs.WriteByte(83);
fs.WriteByte(84);
}
}
此外,我建议您使用 Path.Combine
而不是 path + "\" + subpath
。
周年更新 (RS1) 有一个错误,允许长路径在没有清单的情况下工作。对于任何更新的 Windows,您必须将应用程序清单文件项添加到您的项目中。不然不行。
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
我有一个经验:
1) 在桌面应用程序 (.NET 4.7) 中,您不再需要其他任何东西,然后使用带有前缀 @"\?\ 的路径名(不需要清单,在 app.confing 中设置 UseLegacyPathHandling)和所有作品
2) 在 web 应用程序中你必须这样设置:
bool legacyPaths;
if (AppContext.TryGetSwitch("Switch.System.IO.UseLegacyPathHandling", out legacyPaths) && legacyPaths)
{
var switchType = Type.GetType("System.AppContextSwitches");
if (switchType != null)
{
AppContext.SetSwitch("Switch.System.IO.UseLegacyPathHandling", false);
var legacyField = switchType.GetField("_useLegacyPathHandling", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
legacyField?.SetValue(null, (Int32)0);
AppContext.TryGetSwitch("Switch.System.IO.UseLegacyPathHandling", out legacyPaths);
Assert.IsFalse(legacyPaths, "Long pathnames are not supported!");
}
}
希望对你有所帮助!