107 votes

Comment traiter les fichiers dont le nom comporte plus de 259 caractères ?

Je travaille sur une application qui parcourt tous les fichiers de certains répertoires et effectue des actions sur ces fichiers. Entre autres, je dois récupérer la taille du fichier et la date à laquelle ce fichier a été modifié.

Certains noms complets de fichiers (répertoire + nom de fichier) étant trop longs, je n'ai pas pu utiliser le .NET Framework. FileInfo qui se limite à MAX_PATH (260 caractères). De nombreuses sources web conseillent d'utiliser les fonctions natives Win32 via P/Invoke pour accéder aux fichiers dont les noms sont trop longs.

Actuellement, le même problème semble se poser avec les fonctions Win32. Par exemple, GetFileAttributesEx (kernel32.dll) échoue avec l'erreur Win32 3 ERROR_PATH_NOT_FOUND pour le chemin de 270 octets.

Le même fichier peut être ouvert avec succès à partir du Bloc-notes2 et affiché avec succès avec l'Explorateur Windows (mais Visual Studio 2010, par exemple, ne parvient pas à l'ouvrir en raison de la limite de 259 caractères¹).

Que puis-je faire pour pouvoir accéder à un fichier lorsque le chemin d'accès est long de 270 caractères ?

Notes :

  • Supprimer ou ignorer les fichiers dont le chemin d'accès comporte plus de 259 caractères n'est pas une solution.

  • Je recherche uniquement des solutions compatibles avec Unicode.

  • L'application fonctionnera sous Windows 2008/Vista ou une version ultérieure avec .NET Framework 4 installé.


¹ Étonnamment, Microsoft Word 2007 échoue, se plaignant que "la disquette est trop petite" sur un ordinateur qui n'a pas de lecteur de disquette, ou que "la mémoire RAM est faible" alors qu'il reste 4 Go de RAM, ou enfin que "le logiciel antivirus [...] doit être mis à jour". Cesseront-ils un jour d'afficher des erreurs aussi stupides et dénuées de sens, au moins dans des produits aussi essentiels que Microsoft Office ?

104voto

Mehrdad Points 70493

Solution .NET 4.6.2

Utiliser le \\?\C:\Verrrrrrrrrrrry long path syntaxe telle que décrite ici .

Solution .NET Core

Cela fonctionne simplement parce que le cadre ajoute la syntaxe du chemin long pour vous.

Solution Pre .NET 4.6.2

Utilisez également la syntaxe du chemin long et la version Unicode de la fonction de l'API Win32 avec P/Invoke. De Nommer les fichiers, les chemins et les espaces de noms :

L'API Windows comporte de nombreuses fonctions qui ont également des versions Unicode pour permettre un chemin d'accès de longueur étendue pour une longueur totale maximale du chemin d'accès de 32 767 caractères. Ce type de chemin est composé d'éléments séparés par des barres obliques inverses, chacun pouvant atteindre la valeur indiquée dans le paramètre lpMaximumComponentLength de la fonction GetVolumeInformation (cette valeur est généralement de 255 caractères). Pour spécifier un chemin de longueur étendue, utilisez l'option \\?\ préfixe. Par exemple, \\?\D:\very long path .

Lecture cette page du support Microsoft pourrait également être intéressante.

Une explication très détaillée est fournie dans Long Paths in .NET par Kim Hamilton sur le blog de l'équipe BCL énumère quelques problèmes dans la gestion de ces chemins qui, selon lui, sont la raison pour laquelle cette syntaxe n'est toujours pas prise en charge directement dans .NET :

Il y a plusieurs raisons pour lesquelles nous étions réticents à ajouter de longs chemins dans le passé, et pour lesquelles nous sommes toujours prudents à ce sujet <...>.

<...> le \\?\ permet non seulement de créer des chemins d'accès longs, mais aussi de transmettre le chemin d'accès au système de fichiers avec un minimum de modifications par les API de Windows. La conséquence est que \\?\ désactive la normalisation des noms de fichiers effectuée par les API Windows, y compris la suppression des espaces de fin, l'expansion des '.' et '...', la conversion des chemins relatifs en chemins complets, etc.<...>

<...> Longs chemins avec le \\?\ Le préfixe peut être utilisé dans la plupart des en rapport avec le dossier Windows, mais pas toutes les API Windows. Par exemple, LoadLibrary<...> échoue si le nom du fichier est plus long que MAX_PATH. <Il existe des exemples similaires dans l'ensemble des API Windows ; des solutions de contournement existent, mais elles sont appliquées au cas par cas.

Un autre facteur <...> est la compatibilité avec d'autres applications Windows et le shell Windows lui-même <...>.

Ce problème étant de plus en plus fréquent, Microsoft s'efforce de le résoudre. En fait, pour compléter Vista, vous remarquerez quelques changements qui réduisent le risque d'atteindre la limite MAX_PATH : de nombreux noms de dossiers spéciaux ont été raccourcis et, plus intéressant encore, l'interpréteur de commandes utilise une fonction de réduction automatique du chemin d'accès <...> pour tenter de les faire tenir en 260 caractères.


Avertissement : Il se peut que vous deviez appeler directement les API Windows, car je pense que le .NET Framework ne prend pas en charge ce type de syntaxe de chemin.

46voto

Wolf5 Points 2906

J'ai créé mon propre LongFile y LongDirectory pour résoudre ce problème. Je l'utilise chaque fois que j'utiliserais normalement System.IO.File .

Il peut y avoir des optimisations, etc., mais il fonctionne bien depuis des années.

public static class LongFile
{
    private const int MAX_PATH = 260;

    public static bool Exists(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.File.Exists(path);
        var attr = NativeMethods.GetFileAttributesW(GetWin32LongPath(path));
        return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_ARCHIVE) == NativeMethods.FILE_ATTRIBUTE_ARCHIVE));
    }

    public static void Delete(string path)
    {
        if (path.Length < MAX_PATH) System.IO.File.Delete(path);
        else
        {
            bool ok = NativeMethods.DeleteFileW(GetWin32LongPath(path));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static void AppendAllText(string path, string contents)
    {
        AppendAllText(path, contents, Encoding.Default);
    }

    public static void AppendAllText(string path, string contents, Encoding encoding)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.AppendAllText(path, contents, encoding);
        }
        else
        {
            var fileHandle = CreateFileForAppend(GetWin32LongPath(path));
            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                var bytes = encoding.GetBytes(contents);
                fs.Position = fs.Length;
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void WriteAllText(string path, string contents)
    {
        WriteAllText(path, contents, Encoding.Default);
    }

    public static void WriteAllText(string path, string contents, Encoding encoding)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.WriteAllText(path, contents, encoding);
        }
        else
        {
            var fileHandle = CreateFileForWrite(GetWin32LongPath(path));

            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                var bytes = encoding.GetBytes(contents);
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void WriteAllBytes(string path, byte[] bytes)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.WriteAllBytes(path, bytes);
        }
        else
        {
            var fileHandle = CreateFileForWrite(GetWin32LongPath(path));

            using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
            {
                fs.Write(bytes, 0, bytes.Length);
            }
        }
    }

    public static void Copy(string sourceFileName, string destFileName)
    {
        Copy(sourceFileName, destFileName, false);
    }

    public static void Copy(string sourceFileName, string destFileName, bool overwrite)
    {
        if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Copy(sourceFileName, destFileName, overwrite);
        else
        {
            var ok = NativeMethods.CopyFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName), !overwrite);
            if (!ok) ThrowWin32Exception();
        }
    }

    public static void Move(string sourceFileName, string destFileName)
    {
        if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Move(sourceFileName, destFileName);
        else
        {
            var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static string ReadAllText(string path)
    {
        return ReadAllText(path, Encoding.Default);
    }

    public static string ReadAllText(string path, Encoding encoding)
    {
        if (path.Length < MAX_PATH) { return System.IO.File.ReadAllText(path, encoding); }
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            return encoding.GetString(data);
        }
    }

    public static string[] ReadAllLines(string path)
    {
        return ReadAllLines(path, Encoding.Default);
    }

    public static string[] ReadAllLines(string path, Encoding encoding)
    {
        if (path.Length < MAX_PATH) { return System.IO.File.ReadAllLines(path, encoding); }
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            var str = encoding.GetString(data);
            if (str.Contains("\r")) return str.Split(new[] { "\r\n" }, StringSplitOptions.None);
            return str.Split('\n');
        }
    }
    public static byte[] ReadAllBytes(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.File.ReadAllBytes(path);
        var fileHandle = GetFileHandle(GetWin32LongPath(path));

        using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
        {
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            return data;
        }
    }

    public static void SetAttributes(string path, FileAttributes attributes)
    {
        if (path.Length < MAX_PATH)
        {
            System.IO.File.SetAttributes(path, attributes);
        }
        else
        {
            var longFilename = GetWin32LongPath(path);
            NativeMethods.SetFileAttributesW(longFilename, (int)attributes);
        }
    }

    #region Helper methods

    private static SafeFileHandle CreateFileForWrite(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_ALWAYS, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    private static SafeFileHandle CreateFileForAppend(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_NEW, 0, IntPtr.Zero);
        if (hfile.IsInvalid)
        {
            hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
            if (hfile.IsInvalid) ThrowWin32Exception();
        }
        return hfile;
    }

    internal static SafeFileHandle GetFileHandle(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    internal static SafeFileHandle GetFileHandleWithWrite(string filename)
    {
        if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
        SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        if (hfile.IsInvalid) ThrowWin32Exception();
        return hfile;
    }

    public static System.IO.FileStream GetFileStream(string filename, FileAccess access = FileAccess.Read)
    {
        var longFilename = GetWin32LongPath(filename);
        SafeFileHandle hfile;
        if (access == FileAccess.Write)
        {
            hfile = NativeMethods.CreateFile(longFilename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        }
        else
        {
            hfile = NativeMethods.CreateFile(longFilename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
        }

        if (hfile.IsInvalid) ThrowWin32Exception();

        return new System.IO.FileStream(hfile, access);
    }

    [DebuggerStepThrough]
    public static void ThrowWin32Exception()
    {
        int code = Marshal.GetLastWin32Error();
        if (code != 0)
        {
            throw new System.ComponentModel.Win32Exception(code);
        }
    }

    public static string GetWin32LongPath(string path)
    {
        if (path.StartsWith(@"\\?\")) return path;

        if (path.StartsWith("\\"))
        {
            path = @"\\?\UNC\" + path.Substring(2);
        }
        else if (path.Contains(":"))
        {
            path = @"\\?\" + path;
        }
        else
        {
            var currdir = Environment.CurrentDirectory;
            path = Combine(currdir, path);
            while (path.Contains("\\.\\")) path = path.Replace("\\.\\", "\\");
            path = @"\\?\" + path;
        }
        return path.TrimEnd('.'); ;
    }

    private static string Combine(string path1, string path2)
    {
        return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.'); ;
    }

    #endregion

    public static void SetCreationTime(string path, DateTime creationTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
            var fileTime = creationTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref fileTime, ref aTime, ref wTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static void SetLastAccessTime(string path, DateTime lastAccessTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            var fileTime = lastAccessTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref cTime, ref fileTime, ref wTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static void SetLastWriteTime(string path, DateTime lastWriteTime)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            var fileTime = lastWriteTime.ToFileTimeUtc();
            if (!NativeMethods.SetFileTime(handle, ref cTime, ref aTime, ref fileTime))
            {
                throw new Win32Exception();
            }
        }
    }

    public static DateTime GetLastWriteTime(string path)
    {
        long cTime = 0;
        long aTime = 0;
        long wTime = 0;

        using (var handle = GetFileHandleWithWrite(path))
        {
            NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);

            return DateTime.FromFileTimeUtc(wTime);
        }
    }

}

Et un LongDirectory :

public class LongDirectory
{
    private const int MAX_PATH = 260;

    public static void CreateDirectory(string path)
    {
        if (string.IsNullOrWhiteSpace(path)) return;
        if (path.Length < MAX_PATH)
        {
            System.IO.Directory.CreateDirectory(path);
        }
        else
        {
            var paths = GetAllPathsFromPath(GetWin32LongPath(path));
            foreach (var item in paths)
            {
                if (!LongExists(item))
                {
                    var ok = NativeMethods.CreateDirectory(item, IntPtr.Zero);
                    if (!ok)
                    {
                        ThrowWin32Exception();
                    }
                }
            }
        }
    }

    public static void Delete(string path)
    {
        Delete(path, false);
    }

    public static void Delete(string path, bool recursive)
    {
        if (path.Length < MAX_PATH && !recursive)
        {
            System.IO.Directory.Delete(path, false);
        }
        else
        {
            if (!recursive)
            {
                bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(path));
                if (!ok) ThrowWin32Exception();
            }
            else
            {
                DeleteDirectories(new string[] { GetWin32LongPath(path) });
            }
        }
    }

    private static void DeleteDirectories(string[] directories)
    {
        foreach (string directory in directories)
        {
            string[] files = LongDirectory.GetFiles(directory, null, System.IO.SearchOption.TopDirectoryOnly);
            foreach (string file in files)
            {
                LongFile.Delete(file);
            }
            directories = LongDirectory.GetDirectories(directory, null, System.IO.SearchOption.TopDirectoryOnly);
            DeleteDirectories(directories);
            bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(directory));
            if (!ok) ThrowWin32Exception();
        }
    }

    public static bool Exists(string path)
    {
        if (path.Length < MAX_PATH) return System.IO.Directory.Exists(path);
        return LongExists(GetWin32LongPath(path));
    }

    private static bool LongExists(string path)
    {
        var attr = NativeMethods.GetFileAttributesW(path);
        return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_DIRECTORY) == NativeMethods.FILE_ATTRIBUTE_DIRECTORY));
    }

    public static string[] GetDirectories(string path)
    {
        return GetDirectories(path, null, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetDirectories(string path, string searchPattern)
    {
        return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption)
    {
        searchPattern = searchPattern ?? "*";
        var dirs = new List<string>();
        InternalGetDirectories(path, searchPattern, searchOption, ref dirs);
        return dirs.ToArray();
    }

    private static void InternalGetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption, ref List<string> dirs)
    {
        NativeMethods.WIN32_FIND_DATA findData;
        IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(path), searchPattern), out findData);

        try
        {
            if (findHandle != new IntPtr(-1))
            {

                do
                {
                    if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) != 0)
                    {
                        if (findData.cFileName != "." && findData.cFileName != "..")
                        {
                            string subdirectory = System.IO.Path.Combine(path, findData.cFileName);
                            dirs.Add(GetCleanPath(subdirectory));
                            if (searchOption == SearchOption.AllDirectories)
                            {
                                InternalGetDirectories(subdirectory, searchPattern, searchOption, ref dirs);
                            }
                        }
                    }
                } while (NativeMethods.FindNextFile(findHandle, out findData));
                NativeMethods.FindClose(findHandle);
            }
            else
            {
                ThrowWin32Exception();
            }
        }
        catch (Exception)
        {
            NativeMethods.FindClose(findHandle);
            throw;
        }
    }

    public static string[] GetFiles(string path)
    {
        return GetFiles(path, null, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetFiles(string path, string searchPattern)
    {
        return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
    }

    public static string[] GetFiles(string path, string searchPattern, System.IO.SearchOption searchOption)
    {
        searchPattern = searchPattern ?? "*";

        var files = new List<string>();
        var dirs = new List<string> { path };

        if (searchOption == SearchOption.AllDirectories)
        {
            //Add all the subpaths
            dirs.AddRange(LongDirectory.GetDirectories(path, null, SearchOption.AllDirectories));
        }

        foreach (var dir in dirs)
        {
            NativeMethods.WIN32_FIND_DATA findData;
            IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(dir), searchPattern), out findData);

            try
            {
                if (findHandle != new IntPtr(-1))
                {

                    do
                    {
                        if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) == 0)
                        {
                            string filename = System.IO.Path.Combine(dir, findData.cFileName);
                            files.Add(GetCleanPath(filename));
                        }
                    } while (NativeMethods.FindNextFile(findHandle, out findData));
                    NativeMethods.FindClose(findHandle);
                }
            }
            catch (Exception)
            {
                NativeMethods.FindClose(findHandle);
                throw;
            }
        }

        return files.ToArray();
    }

    public static void Move(string sourceDirName, string destDirName)
    {
        if (sourceDirName.Length < MAX_PATH || destDirName.Length < MAX_PATH)
        {
            System.IO.Directory.Move(sourceDirName, destDirName);
        }
        else
        {
            var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceDirName), GetWin32LongPath(destDirName));
            if (!ok) ThrowWin32Exception();
        }
    }

    #region Helper methods

    [DebuggerStepThrough]
    public static void ThrowWin32Exception()
    {
        int code = Marshal.GetLastWin32Error();
        if (code != 0)
        {
            throw new System.ComponentModel.Win32Exception(code);
        }
    }

    public static string GetWin32LongPath(string path)
    {

        if (path.StartsWith(@"\\?\")) return path;

        var newpath = path;
        if (newpath.StartsWith("\\"))
        {
            newpath = @"\\?\UNC\" + newpath.Substring(2);
        }
        else if (newpath.Contains(":"))
        {
            newpath = @"\\?\" + newpath;
        }
        else
        {
            var currdir = Environment.CurrentDirectory;
            newpath = Combine(currdir, newpath);
            while (newpath.Contains("\\.\\")) newpath = newpath.Replace("\\.\\", "\\");
            newpath = @"\\?\" + newpath;
        }
        return newpath.TrimEnd('.');
    }

    private static string GetCleanPath(string path)
    {
        if (path.StartsWith(@"\\?\UNC\")) return @"\\" + path.Substring(8);
        if (path.StartsWith(@"\\?\")) return path.Substring(4);
        return path;
    }

    private static List<string> GetAllPathsFromPath(string path)
    {
        bool unc = false;
        var prefix = @"\\?\";
        if (path.StartsWith(prefix + @"UNC\"))
        {
            prefix += @"UNC\";
            unc = true;
        }
        var split = path.Split('\\');
        int i = unc ? 6 : 4;
        var list = new List<string>();
        var txt = "";

        for (int a = 0; a < i; a++)
        {
            if (a > 0) txt += "\\";
            txt += split[a];
        }
        for (; i < split.Length; i++)
        {
            txt = Combine(txt, split[i]);
            list.Add(txt);
        }

        return list;
    }

    private static string Combine(string path1, string path2)
    {
        return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.');
    }

    #endregion
}

NativeMethods :

internal static class NativeMethods
{
    internal const int FILE_ATTRIBUTE_ARCHIVE = 0x20;
    internal const int INVALID_FILE_ATTRIBUTES = -1;

    internal const int FILE_READ_DATA = 0x0001;
    internal const int FILE_WRITE_DATA = 0x0002;
    internal const int FILE_APPEND_DATA = 0x0004;
    internal const int FILE_READ_EA = 0x0008;
    internal const int FILE_WRITE_EA = 0x0010;

    internal const int FILE_READ_ATTRIBUTES = 0x0080;
    internal const int FILE_WRITE_ATTRIBUTES = 0x0100;

    internal const int FILE_SHARE_NONE = 0x00000000;
    internal const int FILE_SHARE_READ = 0x00000001;

    internal const int FILE_ATTRIBUTE_DIRECTORY = 0x10;

    internal const long FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
                                                FILE_WRITE_DATA |
                                                FILE_WRITE_ATTRIBUTES |
                                                FILE_WRITE_EA |
                                                FILE_APPEND_DATA |
                                                SYNCHRONIZE;

    internal const long FILE_GENERIC_READ = STANDARD_RIGHTS_READ |
                                            FILE_READ_DATA |
                                            FILE_READ_ATTRIBUTES |
                                            FILE_READ_EA |
                                            SYNCHRONIZE;

    internal const long READ_CONTROL = 0x00020000L;
    internal const long STANDARD_RIGHTS_READ = READ_CONTROL;
    internal const long STANDARD_RIGHTS_WRITE = READ_CONTROL;

    internal const long SYNCHRONIZE = 0x00100000L;

    internal const int CREATE_NEW = 1;
    internal const int CREATE_ALWAYS = 2;
    internal const int OPEN_EXISTING = 3;

    internal const int MAX_PATH = 260;
    internal const int MAX_ALTERNATE = 14;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct WIN32_FIND_DATA
    {
        public System.IO.FileAttributes dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public uint nFileSizeHigh; //changed all to uint, otherwise you run into unexpected overflow
        public uint nFileSizeLow;  //|
        public uint dwReserved0;   //|
        public uint dwReserved1;   //v
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
        public string cAlternate;
    }

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

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool CopyFileW(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern int GetFileAttributesW(string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool DeleteFileW(string lpFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool MoveFileW(string lpExistingFileName, string lpNewFileName);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool GetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);

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

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

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool FindClose(IntPtr hFindFile);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool RemoveDirectory(string path);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    internal static extern int SetFileAttributesW(string lpFileName, int fileAttributes);
}

23voto

TripleAntigen Points 753

Vous pouvez essayer la bibliothèque Delimon, une bibliothèque basée sur le .NET Framework 4 sur Microsoft TechNet pour surmonter le problème des noms de fichiers longs :

Bibliothèque Delimon.Win32.IO (V4.0).

Il possède ses propres versions des méthodes clés de System.IO. Par exemple, vous pouvez remplacer :

System.IO.Directory.GetFiles

avec

Delimon.Win32.IO.Directory.GetFiles

qui vous permettra de traiter des fichiers et des dossiers longs.

Extrait du site web :

Delimon.Win32.IO remplace les fonctions de fichiers de base de System.IO et prend en charge les noms de fichiers et de dossiers jusqu'à 32 767 caractères.

Cette bibliothèque est écrite sur .NET Framework 4.0 et peut être utilisée soit sur les systèmes x86 et x64. Les limitations des fichiers et dossiers de la bibliothèque standard System.IO peut fonctionner avec des fichiers dont le nom comporte 260 caractères. 260 caractères dans un nom de fichier et 240 caractères dans un nom de dossier (MAX_PATH est généralement est généralement configuré à 260 caractères). [ ] Exception System.IO.PathTooLong avec la bibliothèque standard .NET.

12voto

Demetri Points 715

6voto

Brooks Points 51

J'ai rencontré ce problème une fois avec une application que j'étais en train d'écrire. Lorsque j'étais sur le point d'atteindre la limite des 260 caractères, je faisais correspondre un lecteur réseau, à la volée, à un segment du chemin complet, ce qui réduisait considérablement la longueur du chemin complet + le nom du fichier. Ce n'est pas vraiment une solution élégante, mais elle a permis de faire le travail.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X