Meilleur moyen de résoudre l'exception de chemin de fichier trop long

109

J'ai créé une application qui télécharge toutes les bibliothèques de documents dans un site SP, mais à un moment donné, cela me donne cette erreur (j'ai essayé de regarder Google mais je n'ai rien trouvé, maintenant si quelqu'un connaît une astuce pour résoudre ce problème, veuillez répondre autrement merci pour le regarder)

System.IO.PathTooLongException: le chemin d'accès spécifié, le nom de fichier ou les deux sont trop longs. Le nom de fichier complet doit comporter moins de 260 caractères et le nom du répertoire doit comporter moins de 248 caractères. à System.IO.Path.NormalizePathFast (chemin de chaîne, booléen fullCheck) à System.IO.Path.GetFullPathInternal (chemin de chaîne) à System.IO.FileStream.Init (chemin de chaîne, mode FileMode, accès FileAccess, droits Int32, utilisation booléenneRights , Partage FileShare, Int32 bufferSize, Options FileOptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) sur System.IO.FileStream..ctor (chemin de chaîne, mode FileMode, accès FileAccess, partage FileShare, Int32 bufferSize, options FileOptions) sur System. IO.File.Create (chemin de chaîne)

il atteint la limite de la chaîne, le code est donné ci-dessous,

#region Downloading Schemes

    private void btnDownload_Click(object sender, EventArgs e)
    {
        TreeNode currentNode = tvWebs.SelectedNode;
        SPObjectData objectData = (SPObjectData)currentNode.Tag;
        try
        {
            CreateLoggingFile();
            using (SPWeb TopLevelWeb = objectData.Web)
            {
                if(TopLevelWeb != null)
                    dwnEachWeb(TopLevelWeb, TopLevelWeb.Title, tbDirectory.Text);
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine(string.Format("Exception caught when tried to pass TopLevelWeb:{1}, Title = {2}, object data to (dwnEachWeb_method), Exception: {0}", ex.ToString(), objectData.Web, objectData.Title));
        }
        finally
        {
            CloseLoggingFile();
        }
    }

    private void dwnEachWeb(SPWeb TopLevelWeb, string FolderName, string CurrentDirectory)
    {
        if (TopLevelWeb != null)
        {
            if (TopLevelWeb.Webs != null)
            {
                CurrentDirectory = CurrentDirectory + "\\" + TopLevelWeb.Title;
                CreateFolder(CurrentDirectory);
                foreach (SPWeb ChildWeb in TopLevelWeb.Webs)
                {

                    dwnEachWeb(ChildWeb, ChildWeb.Title, CurrentDirectory);
                    ChildWeb.Dispose();
                }
                dwnEachList(TopLevelWeb, CurrentDirectory);
                //dwnEachList(TopLevelWeb, FolderName, CurrentDirectory);
            }
        }
    }

    private void dwnEachList(SPWeb oWeb, string CurrentDirectory)
    {
        foreach (SPList oList in oWeb.Lists)
        {
            if (oList is SPDocumentLibrary && !oList.Hidden)
            {
                dwnEachFile(oList.RootFolder, CurrentDirectory);
            }
        }
    }

    private void dwnEachFile(SPFolder oFolder, string CurrentDirectory)
    {
        if (oFolder.Files.Count != 0)
        {
            CurrentDirectory = CurrentDirectory + "\\" + oFolder.Name;
            CreateFolder(CurrentDirectory);
            foreach (SPFile ofile in oFolder.Files)
            {
                if (CreateDirectoryStructure(CurrentDirectory, ofile.Url))
                {
                    var filepath = System.IO.Path.Combine(CurrentDirectory, ofile.Url);
                    byte[] binFile = ofile.OpenBinary();
                    System.IO.FileStream fstream = System.IO.File.Create(filepath);
                    fstream.Write(binFile, 0, binFile.Length);
                    fstream.Close();
                }
            }
        }
    }

    //creating directory where files will be download        
    private bool CreateDirectoryStructure(string baseFolder, string filepath)
    {
        if (!Directory.Exists(baseFolder)) return false;

        var paths = filepath.Split('/');

        for (var i = 0; i < paths.Length - 1; i++)
        {
            baseFolder = System.IO.Path.Combine(baseFolder, paths[i]);
            Directory.CreateDirectory(baseFolder);
        }
        return true;
    }

    //creating folders
    private bool CreateFolder(string CurrentDirectory)
    {
        if (!Directory.Exists(CurrentDirectory))
        {
            Directory.CreateDirectory(CurrentDirectory);
        }
        return true;
    }

    //shorting string

    #endregion
Muhammad Raja
la source
1
Convertissez le chemin UNC (ou autre) au format 8.3. [Convertir au format 8.3 en utilisant CMD] [1] [1]: stackoverflow.com/questions/10227144/…
AutomationNation
Copie possible. Ici, j'ai trouvé la solution stackoverflow.com/a/44211420/5312148
Francesco

Réponses:

58

La cause de l'erreur étant évidente, voici quelques informations qui devraient vous aider à résoudre le problème:

Voir cet article MS sur l'attribution de noms aux fichiers, chemins et espaces de noms

Voici une citation du lien:

Limitation de la longueur maximale du chemin Dans l'API Windows (à quelques exceptions près décrites dans les paragraphes suivants), la longueur maximale d'un chemin est MAX_PATH, qui est définie comme 260 caractères. Un chemin d'accès local est structuré dans l'ordre suivant: lettre de lecteur, deux-points, barre oblique inverse, composants de nom séparés par des barres obliques inverses et un caractère nul de fin. Par exemple, le chemin maximal sur le lecteur D est "D: \ une chaîne de chemin de 256 caractères <NUL>" où "<NUL>" représente le caractère nul de fin invisible pour la page de codes système actuelle. (Les caractères <> sont utilisés ici pour la clarté visuelle et ne peuvent pas faire partie d'une chaîne de chemin valide.)

Et quelques solutions de contournement (tirées des commentaires):

Il existe des moyens de résoudre les différents problèmes. L'idée de base des solutions énumérées ci-dessous est toujours la même: réduire la longueur du chemin afin d'avoir path-length + name-length < MAX_PATH. Tu peux:

  • Partager un sous-dossier
  • Utilisez la ligne de commande pour attribuer une lettre de lecteur au moyen de SUBST
  • Utilisez AddConnection sous VB pour attribuer une lettre de lecteur à un chemin
James Hill
la source
7
@TimeToThine, avez-vous lu l'article que j'ai publié? Avez-vous lu les commentaires? Je peux me tromper, mais je ne pense pas que vous obtiendrez plus d'aide de la communauté SO, autre que ce que j'ai déjà fourni.
James Hill
2
Oui, j'ai déjà lu cela avant de poster ma question ici, j'ai même essayé "\\? \" Mais pour une raison quelconque, cela ne fonctionne pas dans ce contexte. Je trouve ce blog, en l'utilisant mais pour une raison quelconque, il ne fonctionne pas correctement, " codinghorror.com/blog/2006/08/shortening-long-file-paths.html " Je cherche toujours quelque chose qui garde le répertoire enregistré et je peux prenez-le à partir de là, ou quelque chose comme ça, par exemple utilisez une étiquette cachée pour enregistrer le répertoire courant au lieu de string, mais ne savez pas si cela fonctionnera.
Muhammad Raja le
24
C'est évident mais cela n'a aucun sens. Pourquoi y a-t-il une limitation de taille de chemin ??? c'est 2017.
Jaider
2
Si je modifiais le répertoire actuel vers le répertoire du dossier en utilisant Directory.SetCurrentDirectory (), cela éviterait cette restriction. Ou le problème existerait-il encore.
Adam Lindsay
3
L'article semble avoir été mis à jour: Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. mais vous devez vous inscrire et définir une clé de registre pour l'activer.
Tom Deblauwe
28

La solution qui a fonctionné pour moi était de modifier la clé de registre pour activer le comportement de chemin long, en définissant la valeur sur 1. Il s'agit d'une nouvelle fonctionnalité d'activation pour Windows 10

HKLM\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled (Type: REG_DWORD)

J'ai obtenu cette solution dans une section nommée de l'article que @ james-hill a publié.

https://docs.microsoft.com/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation

goonerify
la source
2
J'ai mis cet ensemble à 1 et j'obtiens toujours l'erreur, je ne sais pas pourquoi à ce stade.
Mr Angry
L'article mentionne deux exigences. Premièrement, la clé de registre, et deuxièmement le xml de l'application: <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings xmlns:ws2="https://schemas.microsoft.com/SMI/2016/WindowsSettings"> <ws2:longPathAware>true</ws2:longPathAware> </windowsSettings> </application>pour moi dans Visual Studio 2019, cette deuxième exigence n'était pas nécessaire après le redémarrage de Visual Studio.
Tom Anderson
Je suis désolé, c'est probablement une question stupide, mais qu'est-ce que "application xml"? Est-ce web.config ou autre chose? J'ai ce problème sur le projet asp.net de page Web
Ondra Starenko
Comme indiqué ci-dessus, cela fonctionne correctement dans Visual Studio 2019 (après le redémarrage) sans changer le xml de l'application. Merci pour la solution.
Zoman
@TomAnderson: J'utilise VS2017. Où puis-je trouver ce fichier application.xml? comme après avoir fait la 1ère étape ne résout pas mon problème.
Sharad
3

Vous pouvez créer un lien symbolique avec un répertoire plus court. Commencez par ouvrir la ligne de commande par exemple Shift + RightClickdans le dossier souhaité avec un chemin plus court (vous devrez peut-être l'exécuter en tant qu'administrateur).

Tapez ensuite avec des chemins relatifs ou absolus:

mklink ShortPath\To\YourLinkedSolution C:\Path\To\Your\Solution /D

Et puis démarrez la solution à partir du chemin le plus court. L'avantage ici est: vous n'avez rien à déplacer.

Markus Weber
la source
Cela ne fonctionne pas dans VS2015. Il semblerait que VS prévalide sur la longueur du chemin. Voir la réponse N-Ate pour contourner VS2015.
N-mangé
1
Ce que vous pouvez faire est de mapper le dossier de solution à un pilote en utilisant la commande "subst". Cela fonctionne pour VS2017.
Filipe Calasans
2

Sous Windows 8.1, en utilisant. NET 3.5, j'ai eu un problème similaire.
Bien que le nom de mon fichier ne contienne que 239 caractères, lorsque je suis allé instancier un objet FileInfo avec juste le nom de fichier (sans chemin), une exception de type System s'est produite. IO.PathTooLongException

2014-01-22 11:10:35 DEBUG LogicalDOCOutlookAddIn.LogicalDOCAddIn - fileName.Length: 239 
2014-01-22 11:10:35 ERROR LogicalDOCOutlookAddIn.LogicalDOCAddIn - Exception in ImportEmail System.IO.PathTooLongException: Percorso e/o nome di file specificato troppo lungo. Il nome di file completo deve contenere meno di 260 caratteri, mentre il nome di directory deve contenere meno di 248 caratteri.
   in System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)
   in System.IO.FileInfo..ctor(String fileName)
   in LogicalDOCOutlookAddIn.LogicalDOCAddIn.GetTempFilePath(String fileName) in C:\Users\alle\Documents\Visual Studio 2010\Projects\MyAddin1Outlook20072010\MyAddin1Outlook20072010\LogicalDOCAddIn.cs:riga 692
   in LogicalDOCOutlookAddIn.LogicalDOCAddIn.ImportEmail(_MailItem mailItem, OutlookConfigXML configXML, Int64 targetFolderID, String SID) in C:\Users\alle\Documents\Visual Studio 2010\Projects\MyAddin1Outlook20072010\MyAddin1Outlook20072010\LogicalDOCAddIn.cs:riga 857
   in LogicalDOCOutlookAddIn.LogicalDOCAddIn.ImportEmails(Explorers explorers, OutlookConfigXML configXML, Int64 targetFolderID, Boolean suppressResultMB) in C:\Users\alle\Documents\Visual Studio 2010\Projects\MyAddin1Outlook20072010\MyAddin1Outlook20072010\LogicalDOCAddIn.cs:riga 99

J'ai résolu le problème en réduisant le nom du fichier à 204 caractères (extension incluse).

Marcel Piquet
la source
Informations supplémentaires pour quiconque lit ceci - Les noms de fichiers sont limités à 247 caractères tandis que le chemin complet est limité à 259. Donc, si votre nom de fichier est 239, cela ne laisse que 20 caractères pour le reste du chemin (par exemple "c: \ temp") . Si vous coupez le nom de fichier, vous devez vous assurer que le chemin d'accès COMPLET est de 259 caractères ou moins.
Losbear
1

Si vous rencontrez un problème avec vos fichiers bin en raison d'un chemin d'accès long, dans Visual Studio 2015, vous pouvez accéder à la page de propriétés du projet incriminé et modifier le répertoire de sortie relatif en un répertoire plus court.

Par exemple, bin \ debug \ devient C: \ _ bins \ MyProject \

N-mangé
la source
1
Après avoir rouvert les propriétés lorsque ma construction a échoué, j'ai remarqué que le nouveau chemin "c: \ vs \ bin \ Release" était remplacé par ".. \ .. \ .. \ .. \ .. \ .. \ .. \. . \ vs \ bin \ Release \ " . Je ne sais pas si ".. \" est pris en compte dans le nombre de caractères.
samis
2
Les chemins évalués comme trop longs sont des chemins absolus.
N-mangé le
1

Ce qui a fonctionné pour moi, c'est de déplacer mon projet tel qu'il était sur le bureau (C: \ Users \ lachezar.l \ Desktop \ MyFolder) vers (C: \ 0 \ MyFolder) qui, comme vous pouvez le voir, utilise un chemin plus court et le réduit a résolu le problème.

Lachezar Lalov
la source
1

D'après mon expérience, je ne recommanderai pas ma réponse ci-dessous pour les applications Web publiques.

Si vous en avez besoin pour vos outils internes ou pour des tests, je vous recommande de le partager sur votre propre machine.

-Right click on the root path you need to access
-Choose Properties
-Click on Share button and add your chosen users who can access it

Cela créera alors un répertoire partagé comme \\ {PCName} \ {YourSharedRootDirectory} Cela pourrait être certainement beaucoup moins que votre chemin complet j'espère, pour moi je pourrais réduire à 30 caractères d'environ 290 caractères. :)

Riyaz Hameed
la source
0

Pas de mention pour l'instant et une mise à jour, il existe une bibliothèque très bien établie pour gérer les chemins trop longs. AlphaFS est une bibliothèque .NET fournissant des fonctionnalités de système de fichiers Win32 plus complètes à la plate-forme .NET que les classes System.IO standard. Le défaut le plus notable du .NET System.IO standard est le manque de prise en charge des fonctionnalités avancées de NTFS, notamment la prise en charge des chemins de longueur étendue (par exemple, les chemins de fichiers / répertoires de plus de 260 caractères).

Markus
la source
0

La meilleure réponse que je puisse trouver, est dans l'un des commentaires ici. L'ajouter à la réponse pour que quelqu'un ne manque pas le commentaire et devrait absolument l'essayer. Cela a résolu le problème pour moi.

Nous devons mapper le dossier de solution sur un lecteur à l'aide de la commande "subst" dans l'invite de commande - par exemple, subst z:

Et puis ouvrez la solution à partir de ce lecteur (z dans ce cas). Cela raccourcirait le chemin autant que possible et pourrait résoudre le long problème de nom de fichier.

Jatin Nath Prusty
la source
0

Cela peut aussi être une solution. Cela se produit parfois aussi lorsque vous gardez votre projet de développement trop profond, ce qui signifie que le répertoire du projet peut avoir trop de répertoires, veuillez donc ne pas créer trop de répertoires pour le conserver dans un simple dossier à l'intérieur du disques. Par exemple - j'obtenais également cette erreur lorsque mon projet était conservé comme ceci -

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication020120 \ GenericSurveyApplication \ GenericSurveyApplication

puis j'ai simplement collé mon projet à l'intérieur

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication

Et le problème a été résolu.

user3820036
la source