Подтвердить что ты не робот

Ошибка при использовании длинных путей в .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: 'Не удалось найти часть path '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.

4b9b3361

Ответ 1

Обновление Anniversary (RS1) имеет ошибку, которая позволяет длинным путям работать без манифеста. Для любых обновленных окон вы должны добавить элемент манифеста приложения в свой проект. В противном случае это не сработает.

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

Ответ 2

Это может не ответить на ваш вопрос, но дать вам подсказку об обходном пути. Я тестировал ваш фрагмент с моно 4.5 под Ubuntu Linux и работает как прелесть, но в Windows эта история может быть немного иной. Здесь виноват, по-видимому, сама .NET Framework, касающаяся этой статьи и эта другая статья, не поддерживает длинные пути.

Следовательно, решение как @Anastasiosyal предлагает в fooobar.com/info/560961/... полагаться на сам Windows Api. Существует два способа: прямой обход или вызов Api.

Directory.CreateDirectory(@"\\?\" + veryLongPath);

Апи звонок (код не мой, получил его от @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.