web-dev-qa-db-fra.com

Meilleure façon de résoudre le chemin d'accès au fichier exception trop longue

J'ai créé une application qui télécharge toutes les bibliothèques de documents d'un site SP, mais elle m'a parfois causé cette erreur (j'ai essayé de regarder Google mais je ne pouvais rien trouver; maintenant, si quelqu'un connaît un problème à résoudre ce problème s'il vous plaît répondez sinon merci de le regarder)

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

il atteint la limite pour 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
89
Muhammad Raja

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

Voir ceci article de MS sur la dénomination des fichiers, des chemins et des espaces de noms

Voici une citation du lien:

Limitation maximale de la longueur du chemin Dans l'API Windows (à quelques exceptions décrites dans les paragraphes suivants), la longueur maximale d'un chemin est MAX_PATH, définie comme suit: 260 caractères. Un chemin local est structuré dans l'ordre suivant: lettre de lecteur, deux points, barre oblique inverse, nom des composants 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 divers problèmes. L'idée de base des solutions listées ci-dessous est toujours la même: Réduisez la longueur du chemin pour avoir path-length + name-length < MAX_PATH. Tu peux:

  • Partager un sous-dossier
  • Utilisez la ligne de commande pour attribuer une lettre de lecteur à l'aide de SUBST
  • Utilisez AddConnection sous VB pour attribuer une lettre de lecteur à un chemin.
51
James Hill

Il existe une bibliothèque appelée Zeta Long Paths qui fournit une API .NET pour travailler avec des chemins longs.

Voici un bon article qui couvre ce problème à la fois pour .NET et PowerShell: " .NET, Exception trop longue du chemin PowerShell et un clone .NET PowerShell Robocopy "

23
Tim Lewis

La solution qui a fonctionné pour moi a consisté à modifier la clé de registre afin d'activer le comportement de chemin d'accès long, en définissant la valeur sur 1. Il s'agit d'une nouvelle fonctionnalité d'adhésion pour Windows 10.

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

J'ai trouvé cette solution dans une section nommée de l'article posté par @ james-hill.

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

12
goonerify

Sous Windows 8.1, utilisez. NET 3.5, j'ai eu un problème similaire.
Bien que le nom de mon fichier ne contienne que 239 caractères, je suis allé instancier un objet FileInfo uniquement avec le nom du fichier (sans chemin), exception du type Système. 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 coupant le nom du fichier à 204 caractères (extension incluse).

2
Marcel Piquet

Vous pouvez créer un lien symbolique avec un répertoire plus court. Tout d'abord ligne de commande ouverte par exemple par Shift + RightClick dans le dossier de votre choix avec un chemin plus court (vous devrez peut-être l'exécuter en tant qu'administrateur).

Puis tapez 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 que vous ne devez rien déplacer.

2
Markus Weber

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. problème.

1
Lachezar Lalov

D'après mon expérience, je ne recommanderai pas la réponse ci-dessous pour les applications Web destinées au public.

Si vous en avez besoin pour vos outils internes ou pour les tests, je vous recommanderais de les partager sur votre propre ordinateur.

-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é du type \\ {PCName}\{YourSharedRootDirectory}. Cela pourrait être nettement inférieur à votre chemin complet. J'espère que je pourrais réduire de 30 à 30 caractères environ 290 caractères. :)

1
user1570636

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

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

1
N-ate

Sans mentionner jusqu'ici 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 à la plate-forme .NET une fonctionnalité plus complète du système de fichiers Win32 que les classes standard System.IO. La lacune la plus notable du système standard .NET System.IO est le manque de prise en charge des fonctionnalités NTFS avancées, notamment la prise en charge des chemins de longueur étendue (chemins de fichiers/répertoires de plus de 260 caractères, par exemple).

0
Markus Hooge

La meilleure réponse que je puisse trouver est dans l'un des commentaires ici. En l'ajoutant à la réponse afin que personne ne rate le commentaire et qu'il soit certain de l'essayer. Cela a résolu le problème pour moi.

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

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

0
Jatin Nath Prusty