Как создать файл по пути длиной более 256 символов?
От: mDmitriy Россия  
Дата: 28.09.15 14:27
Оценка:
Всем привет!

Есть примерно такой код:
var myStrings = new string[10];
... // заполняем массив
File.WriteAllLines(Path.Combine(outputPath, "MyFile.dat"), myStrings);

Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов
Как быть?
Спасибо...
Re: Как создать файл по пути длиной более 256 символов?
От: Sinix  
Дата: 28.09.15 14:39
Оценка: 18 (2)
Здравствуйте, mDmitriy, Вы писали:

D>Как быть?

По возможности не использовать длинные пути к файлам. Если не свезло — см
https://gallery.technet.microsoft.com/DelimonWin32IO-Library-V40-7ff6b16c
или любой из
https://www.nuget.org/packages?q=long+path

Также см. объяснение от BCL Team на тему "почему не?"
http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx
Re: Как создать файл по пути длиной более 256 символов?
От: BratGanjubas Россия  
Дата: 28.09.15 18:50
Оценка: 7 (2) +1
Здравствуйте, mDmitriy, Вы писали:

D>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов

D>Как быть?
D>Спасибо...

https://www.nuget.org/packages/Microsoft.Experimental.IO/
Re: Как создать файл по пути длиной более 256 символов?
От: _Raz_  
Дата: 28.09.15 19:31
Оценка: 3 (1)
Здравствуйте, mDmitriy, Вы писали:

D>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов

D>Как быть?

В свое время мы использовали AlphaFS. Хотя для задачи исключительно поддержки длинных путей она может быть тяжеловата.
... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 78>>
Re: Всем огромное спасибо...
От: mDmitriy Россия  
Дата: 29.09.15 07:58
Оценка: 38 (1)
А вообще странная ситуация:
Directory.CreateDirectory(myLongPath) работает только из пакета Pri.LongPath (да и его пришлось подписывать строгим именем);
File.WriteAllLines(myLongPath, lines) работает только из Delimon.dll.
Задействовать все прочее у меня не получилось...
Отредактировано 30.09.2015 6:45 mDmitriy . Предыдущая версия .
Re[2]: Всем огромное спасибо...
От: seimur  
Дата: 26.11.15 14:52
Оценка:
Здравствуйте, mDmitriy, Вы писали:

D>А вообще странная ситуация:

D>Directory.CreateDirectory(myLongPath) работает только из пакета Pri.LongPath (да и его пришлось подписывать строгим именем);
D>File.WriteAllLines(myLongPath, lines) работает только из Delimon.dll.
D>Задействовать все прочее у меня не получилось...
Сам совсем недавно решал такую проблему для работы с длинными путями.
Тут без WinApi не обойтись.
Могу подкинуть если нужно
Теоретически нет разницы между теорией и практикой, но на практике она есть
Re[3]: Всем огромное спасибо...
От: mDmitriy Россия  
Дата: 26.11.15 19:01
Оценка:
Здравствуйте, seimur, Вы писали:
S>Сам совсем недавно решал такую проблему для работы с длинными путями.
S>Тут без WinApi не обойтись.
S>Могу подкинуть если нужно
Буду благодарен...
Re: Как создать файл по пути длиной более 256 символов?
От: Kolesiki  
Дата: 28.11.15 15:43
Оценка:
Здравствуйте, mDmitriy, Вы писали:

D>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов

D>Как быть?

В первую очередь я бы пересмотрел алгоритм — если он оперирует сущностями, которые уже превышают пределы, никто не гарантирует, что завтра вы не превысите даже расширенные пределы. Да и странновато как-то использовать данные для генерации путей хранения (а если там кракозябры-двоеточия-бэкслэши?). В похожей задаче, где надо было хранить кэш URL'ек, я вычислял хэш и уже из него делал файл.
Re: Как создать файл по пути длиной более 256 символов?
От: Vladek Россия Github
Дата: 02.12.15 23:40
Оценка:
Здравствуйте, mDmitriy, Вы писали:

D>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов

D>Как быть?

Надо в начале пути добавить "\\?\" и всё вроде бы должно заработать.
Re[4]: Всем огромное спасибо...
От: seimur  
Дата: 07.12.15 12:03
Оценка:
Здравствуйте, mDmitriy, Вы писали:

D>Здравствуйте, seimur, Вы писали:

S>>Сам совсем недавно решал такую проблему для работы с длинными путями.
S>>Тут без WinApi не обойтись.
S>>Могу подкинуть если нужно
D>Буду благодарен...

namespace System.IO.LongPathExtension
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

/// <summary>
/// Usefull extension methods to work with collections.
/// </summary>
public static class CollectionExtension
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}

public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
{
action(item);
}
}
}

/// <summary>
///
/// </summary>
public class FileSystemObject
{
private const string SearchAllCriteria = "*";

private uint m_Attributes;
private FileSystemObject m_Parent;

/// <summary>
/// Returns path to file system object.
/// </summary>
public string Path { get; private set; }

/// <summary>
/// Returns an UNC path to file system object to work with Windows32 API.
/// </summary>
public string Unc
{
get
{
if (Path.StartsWith(@"\\?\") || Path.StartsWith(@"\\?\UNC\"))
{
return Path;
}

return (Path.StartsWith(@"\\")) ? @"\\?\UNC\" + (Path.Remove(0, 2)) : @"\\?\" + Path;
}
}

/// <summary>
/// Returns the name of file system object.
/// </summary>
public string Name { get { return System.IO.Path.GetFileName(Path); } }

/// <summary>
/// Returns file attributes.
/// </summary>
private FileAttributes Attributes
{
get { return (FileAttributes)m_Attributes; }
set
{
if (!Exists) { throw new IOException(string.Format("Neither file nor directory {0} is found", Path)); }

if ((FileAttributes)m_Attributes != value)
{
m_Attributes = (uint)value;
CheckError(SetFileAttributes(Unc, m_Attributes));
}
}
}

/// <summary>
/// Checks whether the file is readonly or not.
/// </summary>
public bool Readonly
{
get
{
return Exists && (Attributes.HasFlag(FileAttributes.ReadOnly));
}
set
{
if (value)
{
Attributes |= FileAttributes.ReadOnly;
}
else
{
Attributes &= ~FileAttributes.ReadOnly;
}
}
}

/// <summary>
/// Parent file system object.
/// </summary>
public FileSystemObject Parent
{
get
{
if (m_Parent == null)
{
if (Path.Length == 2 && Path[1] == ':') { return null; }

int nameStartIndex = Path.LastIndexOf(Name, StringComparison.OrdinalIgnoreCase);
string parentName = Path.Remove(nameStartIndex).TrimEnd(System.IO.Path.DirectorySeparatorChar);

if (parentName.Length > 0) { m_Parent = new FileSystemObject(parentName, INVALID_FILE_HANDLE); }
}
return m_Parent;
}
}

/// <summary>
/// Checks file system object existence.
/// </summary>
public bool Exists
{
get
{
m_Attributes = GetFileAttributes(Unc);
if (m_Attributes == INVALID_FILE_HANDLE)
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode != ERROR_SUCCESS &&
errorCode != ERROR_PATH_NOT_FOUND &&
errorCode != ERROR_FILE_NOT_FOUND)
{
throw new Win32Exception(errorCode);
}
}

return m_Attributes != INVALID_FILE_HANDLE;
}
}

/// <summary>
/// True if file system object is file.
/// </summary>
public bool IsFile { get { return Exists && (m_Attributes & (uint)FileAttributes.Directory) == 0; } }

/// <summary>
/// True if file system object is directory.
/// </summary>
public bool IsDirectory { get { return Exists && (m_Attributes & (uint)FileAttributes.Directory) != 0; } }

/// <summary>
/// Returns file system object children.
/// In case of file system object not being a directory, an empty collection will be returned.
/// </summary>
public ReadOnlyCollection<FileSystemObject> Children
{
get
{
ICollection<FileSystemObject> children = GetChildren(SearchAllCriteria, FileSystemObjectSearch.All);
return new ReadOnlyCollection<FileSystemObject>(children.ToList());
}
}

/// <summary>
/// Initialize new file system object.
/// </summary>
/// <param name="path">Physical path.</param>
public FileSystemObject(string path) : this(path, INVALID_FILE_HANDLE) { }

private FileSystemObject(string path, uint attributes)
{
if (path == null) { throw new ArgumentNullException("path"); }

if (path == String.Empty) { throw new ArgumentException("path cannot be empty."); }

// Removes an UNC prefix if there is any..
Path = path.Replace(@"\\?\UNC\", @"\\").Replace(@"\\?\", String.Empty).TrimEnd(System.IO.Path.DirectorySeparatorChar);

m_Attributes = attributes;
}

/// <summary>
/// Removes file system object.
/// </summary>
/// <param name="recursivelyIfDirectory">In case of directory, the content should be deleted as well.</param>
public void Delete(bool recursivelyIfDirectory = false)
{
if (!Exists) { throw new IOException(string.Format("Neither directory nor file {0} exists.", Path)); }

// To avoid additional call to underlying level(local/network storage) we use bitmask to check.
// m_Attributes is already refreshed by calling to Exists property.
if ((m_Attributes & (uint)FileAttributes.Directory) == 0)
{
CheckError(DeleteFile(Unc));
}
else if (!recursivelyIfDirectory)
{
CheckError(RemoveDirectory(Unc));
}
else
{
ICollection<FileSystemObject> children = Children;
children.ForEach(child => child.Delete(true));
CheckError(RemoveDirectory(Unc));
}
}

/// <summary>
/// Checks result and throws Win32Exception.
/// </summary>
/// <param name="result">Result of Win32 operation.</param>
private static void CheckError(bool result)
{
if (!result) { throw new Win32Exception(); }
}

private ICollection<FileSystemObject> GetChildren(string searchPattern, FileSystemObjectSearch fileSystemObjectSearch)
{
if (!IsDirectory) { throw new DirectoryNotFoundException(Path); }

WIN32_FIND_DATA findData;
IntPtr findHandle = FindFirstFile(Unc + @"\" + searchPattern, out findData);
ICollection<FileSystemObject> levelChildren = new List<FileSystemObject>();
try
{
// Add directory separator char to drive.
if (Path.EndsWith(":")) { Path += System.IO.Path.DirectorySeparatorChar; }

for (bool found = (findHandle != INVALID_HANDLE_VALUE); found; found = FindNextFile(findHandle, out findData))
{
var foundFileSystemObject = new FileSystemObject(System.IO.Path.Combine(Unc, findData.cFileName), (uint)findData.dwFileAttributes);
if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." &&
findData.cFileName != ".." &&
fileSystemObjectSearch != FileSystemObjectSearch.FilesOnly)
{
levelChildren.Add(foundFileSystemObject);
}
}
else
{
if (fileSystemObjectSearch != FileSystemObjectSearch.DirectoriesOnly)
{
levelChildren.Add(foundFileSystemObject);
}
}
}
int errorCode = Marshal.GetLastWin32Error();
CheckError(errorCode == ERROR_FILE_NOT_FOUND || errorCode == ERROR_NO_MORE_FILES || errorCode == ERROR_SUCCESS);
}
finally
{
if (findHandle != INVALID_HANDLE_VALUE) { FindClose(findHandle); }
}

return levelChildren;
}

/// <summary>
/// Get all files from current folder including all files from all subfolders.
/// </summary>
/// <returns>Collection of file system objects.</returns>
public ICollection<FileSystemObject> GetFiles()
{
return GetFiles(SearchAllCriteria, SearchOption.TopDirectoryOnly);
}

/// <summary>
/// Get all files from current folder matching the search criteria and in case of
/// searchOption AllDirectories include files from subfolders.
/// </summary>
/// <param name="searchPattern">Search pattern.</param>
/// <param name="searchOption">Search option: TopDirectoryOnly/AllDirectories</param>
/// <returns></returns>
public ICollection<FileSystemObject> GetFiles(string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
{
if (!IsDirectory) { throw new DirectoryNotFoundException(Path); }

ICollection<FileSystemObject> files = GetChildren(searchPattern, FileSystemObjectSearch.FilesOnly);
if (searchOption == SearchOption.AllDirectories)
{
ICollection<FileSystemObject> directories = GetChildren(SearchAllCriteria, FileSystemObjectSearch.DirectoriesOnly);
foreach (var directory in directories)
{
files.AddRange(directory.GetFiles(searchPattern, searchOption));
}
}

return files;
}

private static bool CreateDirectoryInternal(string uncPath)
{
return CreateDirectory(uncPath, IntPtr.Zero) || Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS;
}

/// <summary>
/// Creates directory.
/// </summary>
/// <param name="recursively"></param>
public void CreateDirectory(bool recursively)
{
if (!CreateDirectoryInternal(Unc))
{
if (Parent == null || !recursively) { throw new Win32Exception(); }

Parent.CreateDirectory(true);
CreateDirectoryInternal(Unc);
}
}

/// <summary>
/// Get whole file structure of specific directory.
/// </summary>
/// <returns></returns>
public ICollection<FileSystemObject> GetFlattenedHierarchy()
{
var resultSet = new List<FileSystemObject>(Children);
var flattenedHierarchy = new List<FileSystemObject>(resultSet);
foreach (var systemObject in flattenedHierarchy.Where(systemObject => systemObject.IsDirectory))
{
resultSet.AddRange(systemObject.GetFlattenedHierarchy());
}

return resultSet;
}

/// <summary>
/// Copy file or directory.
/// </summary>
/// <param name="target">Target file.</param>
/// <param name="overwrite">Overwrite if target file exists.</param>
public void CopyTo(string target, bool overwrite)
{
CopyTo(new FileSystemObject(target), overwrite);
}

/// <summary>
/// Copy file or directory.
/// </summary>
/// <param name="target">Target file.</param>
/// <param name="overwrite">Overwrite if target file exists.</param>
public void CopyTo(FileSystemObject target, bool overwrite)
{
if (target == null) { throw new ArgumentNullException("target"); }
if (!Exists) { throw new IOException(string.Format("Source {0} does not exists.", Path)); }

// To avoid additional call to underlying level(local/network storage) we use bitmask to check.
// m_Attributes is already refreshed by calling to Exists property.
if ((m_Attributes & (uint)FileAttributes.Directory) == 0)
{
CheckError(CopyFile(Unc, target.IsDirectory ? target.Unc + @"\" + Name : target.Unc, !overwrite));
}
else
{
// Copy directory structure..
var targetSubfolder = new FileSystemObject(target.Unc + @"\" + Name);
if (!targetSubfolder.Exists) { targetSubfolder.CreateDirectory(true); }

ICollection<FileSystemObject> children = Children;
children.ForEach(child => child.CopyTo(targetSubfolder, overwrite));
}
}

/// <summary>
/// Move file or directory.
/// </summary>
/// <param name="target">Target file.</param>
public void MoveTo(string target)
{
MoveTo(new FileSystemObject(target));
}

/// <summary>
/// Move file or directory.
/// </summary>
/// <param name="target">Target file.</param>
public void MoveTo(FileSystemObject target)
{
if (target == null) { throw new ArgumentNullException("target"); }
if (!Exists) { throw new IOException(string.Format("Source {0} does not exists.", Path)); }

// To avoid additional call to underlying level(local/network storage) we use bitmask to check.
// m_Attributes is already refreshed by calling to Exists property.
if (!MoveFileEx(Unc, target.Unc + @"\" + Name, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == ERROR_ACCESS_DENIED)
{

// Unable to move folder, use different strategy, moving directory structure manually..
var targetSubfolder = new FileSystemObject(target.Unc + @"\" + Name);
targetSubfolder.CreateDirectory(true);

ICollection<FileSystemObject> children = Children;
children.ForEach(child => child.MoveTo(targetSubfolder));
Delete();
}
else
{
throw new Win32Exception(errorCode);
}
}
}

/// <summary>
/// File access
/// </summary>
[Flags]
public enum WinApiFileAccess : uint
{
/// <summary>
/// GenericRead
/// </summary>
GenericRead = 0x80000000,
/// <summary>
/// GenericWrite
/// </summary>
GenericWrite = 0x40000000,
/// <summary>
/// GenericExecute
/// </summary>
GenericExecute = 0x20000000,
/// <summary>
/// GenericAll
/// </summary>
GenericAll = 0x10000000,
}

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern SafeFileHandle CreateFile(
string lpFileName,
WinApiFileAccess dwDesiredAccess,
FileShare dwShareMode,
IntPtr lpSecurityAttributes,
FileMode dwCreationDisposition,
FileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);

/// <summary>
/// Openes file stream regarding to specified parameters.
/// </summary>
/// <param name="access">File access.</param>
/// <param name="share">File share.</param>
/// <param name="mode">Creation disposition.</param>
/// <returns>Returns opened stream.</returns>
public Stream OpenFileStream(FileAccess access, FileShare share, FileMode mode)
{
return OpenFileStream(Unc, access, share, mode);
}

/// <summary>
/// Openes file stream regarding to specified parameters.
/// </summary>
/// <param name="file">Path to file.</param>
/// <param name="access">File access.</param>
/// <param name="share">File share.</param>
/// <param name="mode">Creation disposition.</param>
/// <returns>Returns opened stream.</returns>
public static Stream OpenFileStream(string file, FileAccess access, FileShare share, FileMode mode)
{
SafeFileHandle fileHandle = CreateFile(file, ConvertFileAccessValue(access), share, IntPtr.Zero, mode, 0, IntPtr.Zero);
CheckError(!fileHandle.IsInvalid);

var targetStream = new FileStream(fileHandle, access);
return targetStream;
}

/// <summary>
/// Read all text from file.
/// </summary>
/// <returns>Returns text content of files.</returns>
public string ReadAllText()
{
using (var reader = new StreamReader(OpenFileStream(FileAccess.Read, FileShare.Read, FileMode.Open)))
{
string fileContent = reader.ReadToEnd();
return fileContent;
}
}

private static WinApiFileAccess ConvertFileAccessValue(FileAccess access)
{
switch (access)
{
case FileAccess.Read:
return WinApiFileAccess.GenericRead;
case FileAccess.Write:
return WinApiFileAccess.GenericWrite;
}
return WinApiFileAccess.GenericRead | WinApiFileAccess.GenericWrite;
}

#region Windows API Parameters/Return Values/Error Codes
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private static uint INVALID_FILE_HANDLE = uint.MaxValue;

#region Error codes
private const int ERROR_SUCCESS = 0;
private const int ERROR_FILE_NOT_FOUND = 0x2;
private const int ERROR_NO_MORE_FILES = 0x12;
private const int ERROR_ALREADY_EXISTS = 0xB7;
private const int ERROR_PATH_NOT_FOUND = 0x03;
private const int ERROR_ACCESS_DENIED = 0x5;
#endregion //Error codes

#region MoveFileEx flags
private const int MOVEFILE_REPLACE_EXISTING = 0x00000001;
private const int MOVEFILE_COPY_ALLOWED = 0x00000002;
#endregion // MoveFileEx flags

#region Windows Api
/// <summary>
/// WIN32_FIND_DATA
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATA
{
public FileAttributes dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternate;
}

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FindClose(IntPtr hFindFile);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteFile(string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool RemoveDirectory(string lpFileName);

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool failIfExists);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern uint GetFileAttributes(string directoryPath);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetFileAttributes(string lpFileName, uint dwFileAttributes);
#endregion //Windows Api
#endregion //Windows API Parameters/Return Values/Error Codes

}

enum FileSystemObjectSearch { FilesOnly, DirectoriesOnly, All }
}
Теоретически нет разницы между теорией и практикой, но на практике она есть
Re[4]: Всем огромное спасибо...
От: seimur  
Дата: 07.12.15 12:06
Оценка:
Здравствуйте, mDmitriy, Вы писали:

D>Здравствуйте, seimur, Вы писали:

S>>Сам совсем недавно решал такую проблему для работы с длинными путями.
S>>Тут без WinApi не обойтись.
S>>Могу подкинуть если нужно
D>Буду благодарен...

namespace System.IO.LongPathExtension
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles;

    /// <summary>
    /// Usefull extension methods to work with collections.
    /// </summary>
    public static class CollectionExtension
    {
        public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                collection.Add(item);
            }
        }

        public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
        {
            foreach (var item in collection)
            {
                action(item);
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class FileSystemObject
    {
        private const string SearchAllCriteria = "*";

        private uint m_Attributes;
        private FileSystemObject m_Parent;

        /// <summary>
        /// Returns path to file system object.
        /// </summary>
        public string Path { get; private set; }

        /// <summary>
        /// Returns an UNC path to file system object to work with Windows32 API.
        /// </summary>
        public string Unc
        {
            get
            {
                if (Path.StartsWith(@"\\?\") || Path.StartsWith(@"\\?\UNC\"))
                {
                    return Path;
                }

                return (Path.StartsWith(@"\\")) ? @"\\?\UNC\" + (Path.Remove(0, 2)) : @"\\?\" + Path;
            }
        }

        /// <summary>
        /// Returns the name of file system object.
        /// </summary>
        public string Name { get { return System.IO.Path.GetFileName(Path); } }

        /// <summary>
        /// Returns file attributes.
        /// </summary>
        private FileAttributes Attributes
        {
            get { return (FileAttributes)m_Attributes; }
            set
            {
                if (!Exists) { throw new IOException(string.Format("Neither file nor directory {0} is found", Path)); }

                if ((FileAttributes)m_Attributes != value)
                {
                    m_Attributes = (uint)value;
                    CheckError(SetFileAttributes(Unc, m_Attributes));
                }
            }
        }

        /// <summary>
        /// Checks whether the file is readonly or not.
        /// </summary>
        public bool Readonly
        {
            get
            {
                return Exists && (Attributes.HasFlag(FileAttributes.ReadOnly));
            }
            set
            {
                if (value)
                {
                    Attributes |= FileAttributes.ReadOnly;
                }
                else
                {
                    Attributes &= ~FileAttributes.ReadOnly;
                }
            }
        }

        /// <summary>
        /// Parent file system object.
        /// </summary>
        public FileSystemObject Parent
        {
            get
            {
                if (m_Parent == null)
                {
                    if (Path.Length == 2 && Path[1] == ':') { return null; }

                    int nameStartIndex = Path.LastIndexOf(Name, StringComparison.OrdinalIgnoreCase);
                    string parentName = Path.Remove(nameStartIndex).TrimEnd(System.IO.Path.DirectorySeparatorChar);

                    if (parentName.Length > 0) { m_Parent = new FileSystemObject(parentName, INVALID_FILE_HANDLE); }
                }
                return m_Parent;
            }
        }

        /// <summary>
        /// Checks file system object existence.
        /// </summary>
        public bool Exists
        {
            get
            {
                m_Attributes = GetFileAttributes(Unc);
                if (m_Attributes == INVALID_FILE_HANDLE)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    if (errorCode != ERROR_SUCCESS &&
                        errorCode != ERROR_PATH_NOT_FOUND &&
                        errorCode != ERROR_FILE_NOT_FOUND)
                    {
                        throw new Win32Exception(errorCode);
                    }
                }

                return m_Attributes != INVALID_FILE_HANDLE;
            }
        }

        /// <summary>
        /// True if file system object is file.
        /// </summary>
        public bool IsFile { get { return Exists && (m_Attributes & (uint)FileAttributes.Directory) == 0; } }

        /// <summary>
        /// True if file system object is directory.
        /// </summary>
        public bool IsDirectory { get { return Exists && (m_Attributes & (uint)FileAttributes.Directory) != 0; } }

        /// <summary>
        /// Returns file system object children.
        /// In case of file system object not being a directory, an empty collection will be returned.
        /// </summary>
        public ReadOnlyCollection<FileSystemObject> Children
        {
            get
            {
                ICollection<FileSystemObject> children = GetChildren(SearchAllCriteria, FileSystemObjectSearch.All);
                return new ReadOnlyCollection<FileSystemObject>(children.ToList());
            }
        }

        /// <summary>
        /// Initialize new file system object.
        /// </summary>
        /// <param name="path">Physical path.</param>
        public FileSystemObject(string path) : this(path, INVALID_FILE_HANDLE) { }

        private FileSystemObject(string path, uint attributes)
        {
            if (path == null) { throw new ArgumentNullException("path"); }

            if (path == String.Empty) { throw new ArgumentException("path cannot be empty."); }

            // Removes an UNC prefix if there is any..
            Path = path.Replace(@"\\?\UNC\", @"\\").Replace(@"\\?\", String.Empty).TrimEnd(System.IO.Path.DirectorySeparatorChar);

            m_Attributes = attributes;
        }

        /// <summary>
        /// Removes file system object.
        /// </summary>
        /// <param name="recursivelyIfDirectory">In case of directory, the content should be deleted as well.</param>
        public void Delete(bool recursivelyIfDirectory = false)
        {
            if (!Exists) { throw new IOException(string.Format("Neither directory nor file {0} exists.", Path)); }

            // To avoid additional call to underlying level(local/network storage) we use bitmask to check.
            // m_Attributes is already refreshed by calling to Exists property.
            if ((m_Attributes & (uint)FileAttributes.Directory) == 0)
            {
                CheckError(DeleteFile(Unc));
            }
            else if (!recursivelyIfDirectory)
            {
                CheckError(RemoveDirectory(Unc));
            }
            else
            {
                ICollection<FileSystemObject> children = Children;
                children.ForEach(child => child.Delete(true));
                CheckError(RemoveDirectory(Unc));
            }
        }

        /// <summary>
        /// Checks result and throws Win32Exception.
        /// </summary>
        /// <param name="result">Result of Win32 operation.</param>
        private static void CheckError(bool result)
        {
            if (!result) { throw new Win32Exception(); }
        }

        private ICollection<FileSystemObject> GetChildren(string searchPattern, FileSystemObjectSearch fileSystemObjectSearch)
        {
            if (!IsDirectory) { throw new DirectoryNotFoundException(Path); }

            WIN32_FIND_DATA findData;
            IntPtr findHandle = FindFirstFile(Unc + @"\" + searchPattern, out findData);
            ICollection<FileSystemObject> levelChildren = new List<FileSystemObject>();
            try
            {
                // Add directory separator char to drive.
                if (Path.EndsWith(":")) { Path += System.IO.Path.DirectorySeparatorChar; }

                for (bool found = (findHandle != INVALID_HANDLE_VALUE); found; found = FindNextFile(findHandle, out findData))
                {
                    var foundFileSystemObject = new FileSystemObject(System.IO.Path.Combine(Unc, findData.cFileName), (uint)findData.dwFileAttributes);
                    if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
                    {
                        if (findData.cFileName != "." &&
                            findData.cFileName != ".." &&
                            fileSystemObjectSearch != FileSystemObjectSearch.FilesOnly)
                        {
                            levelChildren.Add(foundFileSystemObject);
                        }
                    }
                    else
                    {
                        if (fileSystemObjectSearch != FileSystemObjectSearch.DirectoriesOnly)
                        {
                            levelChildren.Add(foundFileSystemObject);
                        }
                    }
                }
                int errorCode = Marshal.GetLastWin32Error();
                CheckError(errorCode == ERROR_FILE_NOT_FOUND || errorCode == ERROR_NO_MORE_FILES || errorCode == ERROR_SUCCESS);
            }
            finally
            {
                if (findHandle != INVALID_HANDLE_VALUE) { FindClose(findHandle); }
            }

            return levelChildren;
        }

        /// <summary>
        /// Get all files from current folder including all files from all subfolders.
        /// </summary>
        /// <returns>Collection of file system objects.</returns>
        public ICollection<FileSystemObject> GetFiles()
        {
            return GetFiles(SearchAllCriteria, SearchOption.TopDirectoryOnly);
        }

        /// <summary>
        /// Get all files from current folder matching the search criteria and in case of 
        /// searchOption AllDirectories include files from subfolders.
        /// </summary>
        /// <param name="searchPattern">Search pattern.</param>
        /// <param name="searchOption">Search option: TopDirectoryOnly/AllDirectories</param>
        /// <returns></returns>
        public ICollection<FileSystemObject> GetFiles(string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
        {
            if (!IsDirectory) { throw new DirectoryNotFoundException(Path); }

            ICollection<FileSystemObject> files = GetChildren(searchPattern, FileSystemObjectSearch.FilesOnly);
            if (searchOption == SearchOption.AllDirectories)
            {
                ICollection<FileSystemObject> directories = GetChildren(SearchAllCriteria, FileSystemObjectSearch.DirectoriesOnly);
                foreach (var directory in directories)
                {
                    files.AddRange(directory.GetFiles(searchPattern, searchOption));
                }
            }

            return files;
        }

        private static bool CreateDirectoryInternal(string uncPath)
        {
            return CreateDirectory(uncPath, IntPtr.Zero) || Marshal.GetLastWin32Error() == ERROR_ALREADY_EXISTS;
        }

        /// <summary>
        /// Creates directory.
        /// </summary>
        /// <param name="recursively"></param>
        public void CreateDirectory(bool recursively)
        {
            if (!CreateDirectoryInternal(Unc))
            {
                if (Parent == null || !recursively) { throw new Win32Exception(); }

                Parent.CreateDirectory(true);
                CreateDirectoryInternal(Unc);
            }
        }

        /// <summary>
        /// Get whole file structure of specific directory.
        /// </summary>
        /// <returns></returns>
        public ICollection<FileSystemObject> GetFlattenedHierarchy()
        {
            var resultSet = new List<FileSystemObject>(Children);
            var flattenedHierarchy = new List<FileSystemObject>(resultSet);
            foreach (var systemObject in flattenedHierarchy.Where(systemObject => systemObject.IsDirectory))
            {
                resultSet.AddRange(systemObject.GetFlattenedHierarchy());
            }

            return resultSet;
        }

        /// <summary>
        /// Copy file or directory.
        /// </summary>
        /// <param name="target">Target file.</param>
        /// <param name="overwrite">Overwrite if target file exists.</param>
        public void CopyTo(string target, bool overwrite)
        {
            CopyTo(new FileSystemObject(target), overwrite);
        }

        /// <summary>
        /// Copy file or directory.
        /// </summary>
        /// <param name="target">Target file.</param>
        /// <param name="overwrite">Overwrite if target file exists.</param>
        public void CopyTo(FileSystemObject target, bool overwrite)
        {
            if (target == null) { throw new ArgumentNullException("target"); }
            if (!Exists) { throw new IOException(string.Format("Source {0} does not exists.", Path)); }

            // To avoid additional call to underlying level(local/network storage) we use bitmask to check.
            // m_Attributes is already refreshed by calling to Exists property.
            if ((m_Attributes & (uint)FileAttributes.Directory) == 0)
            {
                CheckError(CopyFile(Unc, target.IsDirectory ? target.Unc + @"\" + Name : target.Unc, !overwrite));
            }
            else
            {
                // Copy directory structure..
                var targetSubfolder = new FileSystemObject(target.Unc + @"\" + Name);
                if (!targetSubfolder.Exists) { targetSubfolder.CreateDirectory(true); }

                ICollection<FileSystemObject> children = Children;
                children.ForEach(child => child.CopyTo(targetSubfolder, overwrite));
            }
        }

        /// <summary>
        /// Move file or directory.
        /// </summary>
        /// <param name="target">Target file.</param>
        public void MoveTo(string target)
        {
            MoveTo(new FileSystemObject(target));
        }

        /// <summary>
        /// Move file or directory.
        /// </summary>
        /// <param name="target">Target file.</param>
        public void MoveTo(FileSystemObject target)
        {
            if (target == null) { throw new ArgumentNullException("target"); }
            if (!Exists) { throw new IOException(string.Format("Source {0} does not exists.", Path)); }

            // To avoid additional call to underlying level(local/network storage) we use bitmask to check.
            // m_Attributes is already refreshed by calling to Exists property.
            if (!MoveFileEx(Unc, target.Unc + @"\" + Name, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
            {
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode == ERROR_ACCESS_DENIED)
                {

                    // Unable to move folder, use different strategy, moving directory structure manually.. 
                    var targetSubfolder = new FileSystemObject(target.Unc + @"\" + Name);
                    targetSubfolder.CreateDirectory(true);

                    ICollection<FileSystemObject> children = Children;
                    children.ForEach(child => child.MoveTo(targetSubfolder));
                    Delete();
                }
                else
                {
                    throw new Win32Exception(errorCode);
                }
            }
        }

        /// <summary> 
        /// File access 
        /// </summary> 
        [Flags]
        public enum WinApiFileAccess : uint
        {
            /// <summary> 
            /// GenericRead 
            /// </summary> 
            GenericRead = 0x80000000,
            /// <summary> 
            /// GenericWrite 
            /// </summary> 
            GenericWrite = 0x40000000,
            /// <summary> 
            /// GenericExecute 
            /// </summary> 
            GenericExecute = 0x20000000,
            /// <summary> 
            /// GenericAll 
            /// </summary> 
            GenericAll = 0x10000000,
        }

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern SafeFileHandle CreateFile(
            string lpFileName,
            WinApiFileAccess dwDesiredAccess,
            FileShare dwShareMode,
            IntPtr lpSecurityAttributes,
            FileMode dwCreationDisposition,
            FileAttributes dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        /// <summary>
        /// Openes file stream regarding to specified parameters.
        /// </summary>
        /// <param name="access">File access.</param>
        /// <param name="share">File share.</param>
        /// <param name="mode">Creation disposition.</param>
        /// <returns>Returns opened stream.</returns>
        public Stream OpenFileStream(FileAccess access, FileShare share, FileMode mode)
        {
            return OpenFileStream(Unc, access, share, mode);
        }

        /// <summary>
        /// Openes file stream regarding to specified parameters.
        /// </summary>
        /// <param name="file">Path to file.</param>
        /// <param name="access">File access.</param>
        /// <param name="share">File share.</param>
        /// <param name="mode">Creation disposition.</param>
        /// <returns>Returns opened stream.</returns>
        public static Stream OpenFileStream(string file, FileAccess access, FileShare share, FileMode mode)
        {
            SafeFileHandle fileHandle = CreateFile(file, ConvertFileAccessValue(access), share, IntPtr.Zero, mode, 0, IntPtr.Zero);
            CheckError(!fileHandle.IsInvalid);

            var targetStream = new FileStream(fileHandle, access);
            return targetStream;
        }

        /// <summary>
        /// Read all text from file.
        /// </summary>
        /// <returns>Returns text content of files.</returns>
        public string ReadAllText()
        {
            using (var reader = new StreamReader(OpenFileStream(FileAccess.Read, FileShare.Read, FileMode.Open)))
            {
                string fileContent = reader.ReadToEnd();
                return fileContent;
            }
        }

        private static WinApiFileAccess ConvertFileAccessValue(FileAccess access)
        {
            switch (access)
            {
                case FileAccess.Read:
                    return WinApiFileAccess.GenericRead;
                case FileAccess.Write:
                    return WinApiFileAccess.GenericWrite;
            }
            return WinApiFileAccess.GenericRead | WinApiFileAccess.GenericWrite;
        }

        #region Windows API Parameters/Return Values/Error Codes
        private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
        private static uint INVALID_FILE_HANDLE = uint.MaxValue;

        #region Error codes
        private const int ERROR_SUCCESS = 0;
        private const int ERROR_FILE_NOT_FOUND = 0x2;
        private const int ERROR_NO_MORE_FILES = 0x12;
        private const int ERROR_ALREADY_EXISTS = 0xB7;
        private const int ERROR_PATH_NOT_FOUND = 0x03;
        private const int ERROR_ACCESS_DENIED = 0x5;
        #endregion //Error codes

        #region MoveFileEx flags
        private const int MOVEFILE_REPLACE_EXISTING = 0x00000001;
        private const int MOVEFILE_COPY_ALLOWED = 0x00000002;
        #endregion // MoveFileEx flags

        #region Windows Api
        /// <summary>
        /// WIN32_FIND_DATA
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct WIN32_FIND_DATA
        {
            public FileAttributes dwFileAttributes;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
            public int nFileSizeHigh;
            public int nFileSizeLow;
            public int dwReserved0;
            public int dwReserved1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string cFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
            public string cAlternate;
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool FindClose(IntPtr hFindFile);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteFile(string lpFileName);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool RemoveDirectory(string lpFileName);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool failIfExists);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern uint GetFileAttributes(string directoryPath);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        private static extern bool SetFileAttributes(string lpFileName, uint dwFileAttributes);
        #endregion //Windows Api
        #endregion //Windows API Parameters/Return Values/Error Codes

    }

    enum FileSystemObjectSearch { FilesOnly, DirectoriesOnly, All }
}
Теоретически нет разницы между теорией и практикой, но на практике она есть
Re[2]: Как создать файл по пути длиной более 256 символов?
От: seimur  
Дата: 08.12.15 19:58
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Здравствуйте, mDmitriy, Вы писали:


D>>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов

D>>Как быть?

V>Надо в начале пути добавить "\\?\" и всё вроде бы должно заработать.


.NET не умеет работать с UNC путями, тут без WinAPI не обойтись либо использовать какие нибудь сторонние библиотеки если есть
Теоретически нет разницы между теорией и практикой, но на практике она есть
Re: Как создать файл по пути длиной более 256 символов?
От: LWhisper  
Дата: 09.12.15 16:31
Оценка:
Здравствуйте, mDmitriy, Вы писали:
D>Путь outputPath состоит из десятка подкаталогов, но общая длина более 256 символов
D>Как быть?

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CreateDirectory(string path, IntPtr securityAttributes);
http://www.pinvoke.net/default.aspx/kernel32.createdirectory

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile(string filePath, NativeFileAccess desiredAccess, FileShare shareMode, IntPtr securityAttributes, FileMode creationDisposition, NativeFileAttributes flagsAndAttributes, IntPtr templateFile);
http://www.pinvoke.net/default.aspx/kernel32.createfile

Путь должен начинаться с \\?\ (запрет разбора пути) или \\UNC\
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.