问题 在.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:'无法找到部分内容   路径'C:\ Users ... \ Desktop \ zzzzzzzzzz ...

(这实际上是一个奇怪的错误信息。)

app.config已经有:

<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />

更多信息(可能不重要)

我尝试添加如上所述 这个帖子 在其他地方(虽然在评论中指出,在使用.net 4.7时不需要)在app.config下 configuration

<runtime>
  <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>

还是一样的错误。

如果我只使用一个 zzzzzz... 它在桌面上创建它没有错误。

我正在使用VS2017,Windows 10.我尝试了Winforms和WPF。


8282
2017-07-03 15:03


起源

这不是4.7的错误。这是Windows中可用的文件路径限制。默认情况下,它硬编码为260个字符。 - eocron
@eocron没有 UseLegacyPathHandling 设为false。 - NtFreX
您确实意识到UseLegacyPathHandling开关适用于目标应用程序 下面 4.6.2根据链接文章,对吗? - Camilo Terevinto
你必须说服 操作系统,你知道你在做什么。 - Hans Passant
@CamiloTerevinto是的。 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />。 - ispiro


答案:


周年纪念更新(RS1)有一个错误,允许长路径在没有清单的情况下工作。对于任何更新的窗口,您必须将Application Manifest File项添加到项目中。否则它将无法工作。

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
  </windowsSettings>
</application>

9
2017-07-11 14:46



谢谢。 +50(+25)。如果你有这个的来源,这也会很好。但无论如何 - 这解决了这个问题。这解释了为什么有些人似乎没有这个问题,而且我这样做。因为我正在运行Windows 10 Creators更新。 - ispiro


这可能无法回答您的问题,但会给您一个解决方法的提示。我在Ubuntu Linux下使用mono 4.5测试了你的代码片段并且像魅力一样,但在Windows中,故事可能有点不同。在这里,责怪的似乎是.NET Framework本身 本文 和 这篇文章,不支持长路径。

因此,@ Anastasiosyal的解决方案建议在 这个StackOverflow的答案 是依靠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


0
2017-07-11 11:11



谢谢。但.net 不 自.net 4.6.2起支持长路径。至于 Path.Combine,a)这是最好的例子。 b)虽然我普遍认为使用方法更好 - Path.Combine 是一个例外。看到 stackoverflow.com/questions/53102/... 。 - ispiro