Страницы

Поиск по вопросам

суббота, 11 января 2020 г.

Как избежать ошибки PathTooLongException?

#c_sharp #исключения #io


Имеется программа обрабатывающая различные файловые пути (напр.: C:\Users\J.Doe,
\\Server\Share, Z:\Mapped\Drive). Для однозначной обработки файлов их пути приводятся
к UNC-формату, если файл располагается не на локальном диске. Для избежания возникновения
исключения PathTooLongException можно к локальным путям добавлять префикс \\?\, но
в этом случае сам путь не обрабатывается, т.е. не раскрываются ссылки, относительные
пути и т.д.. И насколько я понимаю, это не применимо к UNC-путям (поправьте, если не прав).
Нашел статью .NET 4.6.2 and long paths on Windows 10, но как понятно из названия,
сие работает только с Windows 10 и не работает с UNC, а как быть со старыми версиями
ОС и файлами в сети?

Как принято обходить эту ошибку? Можно ли получить доступ к файлу по UNC пути, если
он длиннее MAX_PATH?
    


Ответы

Ответ 1



К сожалению, на старых версиях Windows придётся прибегать к прямому использованию WinAPI. Примеры кода есть в этой статье, придётся написать собственный вспомогательный класс вместо File. Я пользуюсь вот таким классом: public static class LongPathFile { [Flags] public enum EFileAccess : uint { GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, } [Flags] public enum EFileShare : uint { None = 0x00000000, Read = 0x00000001, Write = 0x00000002, Delete = 0x00000004, } public enum ECreationDisposition : uint { New = 1, CreateAlways = 2, OpenExisting = 3, OpenAlways = 4, TruncateExisting = 5 } [Flags] public enum EFileAttributes : uint { Readonly = 0x00000001, Hidden = 0x00000002, System = 0x00000004, Directory = 0x00000010, Archive = 0x00000020, Device = 0x00000040, Normal = 0x00000080, Temporary = 0x00000100, SparseFile = 0x00000200, ReparsePoint = 0x00000400, Compressed = 0x00000800, Offline = 0x00001000, NotContentIndexed = 0x00002000, Encrypted = 0x00004000, Write_Through = 0x80000000, Overlapped = 0x40000000, NoBuffering = 0x20000000, RandomAccess = 0x10000000, SequentialScan = 0x08000000, DeleteOnClose = 0x04000000, BackupSemantics = 0x02000000, PosixSemantics = 0x01000000, OpenReparsePoint = 0x00200000, OpenNoRecall = 0x00100000, FirstPipeInstance = 0x00080000 } [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 SafeFileHandle GetCreateHandle(string path) { var handle = CreateFile( path, EFileAccess.GenericWrite, EFileShare.None, IntPtr.Zero, ECreationDisposition.CreateAlways, 0, IntPtr.Zero); var lastWin32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) throw new Win32Exception(lastWin32Error); return handle; } public static FileStream Create(string path) { return new FileStream(GetCreateHandle(path), FileAccess.Write); } public static SafeFileHandle GetReadHandle(string path) { var handle = CreateFile( path, EFileAccess.GenericRead, EFileShare.None, IntPtr.Zero, ECreationDisposition.OpenExisting, 0, IntPtr.Zero); var lastWin32Error = Marshal.GetLastWin32Error(); if (handle.IsInvalid) throw new Win32Exception(lastWin32Error); return handle; } public static FileStream OpenRead(string path) { return new FileStream(GetReadHandle(path), FileAccess.Read); } } Использовать так же, как и File.Create/File.OpenRead: using (var file = LongPathFile.Create(path)) stream.CopyTo(file);

Комментариев нет:

Отправить комментарий