Melhor maneira de resolver a exceção muito longa do caminho do arquivo

109

Eu criei um aplicativo que baixa todas as bibliotecas de documentos em um site SP, mas em um ponto ele me deu este erro (eu tentei procurar no google mas não consegui encontrar nada, agora se alguém souber de algum truque para resolver este problema, responda caso contrário, obrigado para olhar para ele)

System.IO.PathTooLongException: o caminho especificado, o nome do arquivo ou ambos são muito longos. O nome completo do arquivo deve ter menos de 260 caracteres e o nome do diretório deve ter menos de 248 caracteres. em System.IO.Path.NormalizePathFast (String path, Boolean fullCheck) em System.IO.Path.GetFullPathInternal (String path) em System.IO.FileStream.Init (String path, modo FileMode, acesso FileAccess, direitos Int32, Boolean useRights , Compartilhamento FileShare, Int32 bufferSize, opções FileOptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) em System.IO.FileStream..ctor (String path, modo FileMode, acesso FileAccess, compartilhamento FileShare, Int32 bufferSize, opções FileOptions) em System. IO.File.Create (String caminho)

atinge o limite de string, o código é fornecido abaixo,

#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
fonte
1
Converta o caminho UNC (ou qualquer outro) em um formato 8.3. [Converter para o formato 8.3 usando CMD] [1] [1]: stackoverflow.com/questions/10227144/…
AutomationNation
Possível duplicata de Como evitar System.IO.PathTooLongException?
Deantwo
Possível duplicata. Aqui encontrei a solução stackoverflow.com/a/44211420/5312148
Francesco

Respostas:

58

Como a causa do erro é óbvia, aqui estão algumas informações que devem ajudá-lo a resolver o problema:

Consulte este artigo da MS sobre como nomear arquivos, caminhos e namespaces

Aqui está uma citação do link:

Limitação máxima do comprimento do caminho Na API do Windows (com algumas exceções discutidas nos parágrafos a seguir), o comprimento máximo para um caminho é MAX_PATH, que é definido como 260 caracteres. Um caminho local é estruturado na seguinte ordem: letra da unidade, dois pontos, barra invertida, componentes de nome separados por barras invertidas e um caractere nulo final. Por exemplo, o caminho máximo na unidade D é "D: \ alguma string de caminho de 256 caracteres <NUL>", onde "<NUL>" representa o caractere nulo de terminação invisível para a página de código do sistema atual. (Os caracteres <> são usados ​​aqui para maior clareza visual e não podem fazer parte de uma string de caminho válida.)

E algumas soluções alternativas (retiradas dos comentários):

Existem maneiras de resolver os vários problemas. A ideia básica das soluções listadas abaixo é sempre a mesma: Reduza o comprimento do caminho para ter path-length + name-length < MAX_PATH. Você pode:

  • Compartilhe uma subpasta
  • Use a linha de comando para atribuir uma letra de unidade por meio de SUBST
  • Use AddConnection em VB para atribuir uma letra de unidade a um caminho
James Hill
fonte
7
@TimeToThine, você leu o artigo que postei? Você leu os comentários? Posso estar errado, mas não acho que você receberá mais ajuda da comunidade SO, além da que já forneci.
James Hill
2
Sim, já li que antes de postar minha dúvida aqui, até tentei "\\? \" Mas por algum motivo não está funcionando nesse contexto. Acho que este blog está usando, mas por algum motivo ele não está funcionando corretamente, " codinghorror.com/blog/2006/08/shortening-long-file-paths.html " Ainda estou procurando por algo que mantenha o diretório salvo e posso pegue a partir daí, ou algo parecido, por exemplo, use um rótulo oculto para salvar o diretório atual ao invés da string, mas não tenho certeza se vai funcionar.
Muhammad Raja
24
É óbvio, mas não faz sentido. Por que existe uma limitação de tamanho do caminho ??? é 2017.
Jaider
2
Se eu alterasse o diretório atual para o diretório da pasta usando Directory.SetCurrentDirectory (), isso evitaria essa restrição. Ou o problema ainda existia.
Adam Lindsay
3
O artigo parece ter sido atualizado: Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. mas você deve ativá-lo e definir uma chave de registro para ativá-lo.
Tom Deblauwe,
28

A solução que funcionou para mim foi editar a chave do registro para permitir o comportamento de caminho longo, definindo o valor como 1. Este é um novo recurso opcional para Windows 10

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

Eu obtive essa solução de uma seção nomeada do artigo que @james-hill postou.

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

goonerificar
fonte
2
Eu tenho isso definido como 1 e ainda estou recebendo o erro, não tenho ideia do por que neste momento.
Sr. Irritado de
O artigo menciona dois requisitos. Em primeiro lugar, a chave de registro e, em segundo lugar, o xml do aplicativo: <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>para mim no Visual Studio 2019, esse segundo requisito não era necessário após reiniciar o Visual Studio.
Tom Anderson
Sinto muito, provavelmente esta é uma pergunta estúpida, mas o que é "aplicativo xml"? É web.config ou algo mais? Eu tenho este problema no projeto asp.net da Página da Web
Ondra Starenko
Como dito acima, ele funciona bem no Visual Studio 2019 (após a reinicialização) sem alterar o xml do aplicativo. Obrigado pela solução.
Zoman
@TomAnderson: Estou usando o VS2017. Onde posso encontrar este application.xml? pois depois de fazer o 1º passo não resolve meu problema.
Sharad
3

Você pode criar um link simbólico com um diretório mais curto. Primeiro abra a linha de comando, por exemplo, porShift + RightClick na pasta desejada com um caminho mais curto (você pode ter que executá-lo como administrador).

Em seguida, digite com caminhos relativos ou absolutos:

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

Em seguida, inicie a solução a partir do caminho mais curto. A vantagem aqui é: você não precisa mover nada.

Markus Weber
fonte
Isso não funciona no VS2015. Parece que o VS está pré-validando o comprimento do caminho. Consulte a resposta da N-Ate para a solução alternativa VS2015.
N-ate
1
O que você pode fazer é mapear a pasta de solução para um driver usando o comando "subst". Isso funciona para o VS2017.
Filipe Calasans
2

No Windows 8.1, usando. NET 3.5, tive um problema semelhante.
Embora o nome do meu arquivo tivesse apenas 239 caracteres, quando fui instanciar um objeto FileInfo apenas com o nome do arquivo (sem caminho), ocorreu uma exceção do tipo System. 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

Resolvi o problema reduzindo o nome do arquivo para 204 caracteres (extensão incluída).

Marcel Piquet
fonte
Informações adicionais para quem ler isto - os nomes de arquivos são limitados a 247 caracteres, enquanto o caminho completo é limitado a 259. Portanto, se o seu nome de arquivo for 239, restam apenas 20 caracteres para o resto do caminho (por exemplo, "c: \ temp") . Se você cortar o nome do arquivo, certifique-se de que o caminho COMPLETO tenha 259 caracteres ou menos.
Losbear
1

Se você estiver tendo um problema com seus arquivos bin devido a um longo caminho, no Visual Studio 2015 você pode ir para a página de propriedades do projeto ofensivo e alterar o diretório de saída relativo para um mais curto.

Por exemplo, bin \ debug \ torna-se C: \ _ bins \ MyProject \

N-ate
fonte
1
Após reabrir as propriedades quando minha construção falhou, notei que o novo caminho "c: \ vs \ bin \ Release" foi substituído por ".. \ .. \ .. \ .. \ .. \ .. \ .. \. . \ vs \ bin \ Release \ " . Não tenho certeza se ".. \" será fatorado na contagem de caracteres.
samis
2
Caminhos avaliados como muito longos são caminhos absolutos.
N-ate
1

O que funcionou para mim foi mover meu projeto como estava na área de trabalho (C: \ Users \ lachezar.l \ Desktop \ MyFolder) para (C: \ 0 \ MyFolder) que, como você pode ver, usa um caminho mais curto e reduzi-lo resolveu o problema.

Lachezar Lalov
fonte
1

Pela minha experiência, não recomendarei minha resposta abaixo para nenhum aplicativo da Web voltado ao público.

Se você precisar dele para suas ferramentas internas ou para testes, recomendo compartilhá-lo em sua própria máquina.

-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

Isso criará um diretório compartilhado como \\ {PCName} \ {YourSharedRootDirectory} Isso pode ser definitivamente muito menos do que seu caminho completo, espero, para mim eu poderia reduzir para 30 caracteres de cerca de 290 caracteres. :)

Riyaz Hameed
fonte
0

Sem mencionar até agora e uma atualização, há uma biblioteca muito bem estabelecida para lidar com caminhos que são muito longos. AlphaFS é uma biblioteca .NET que fornece funcionalidade de sistema de arquivos Win32 mais completa para a plataforma .NET do que as classes System.IO padrão. A deficiência mais notável do .NET System.IO padrão é a falta de suporte de recursos NTFS avançados, mais notavelmente suporte de caminho de comprimento estendido (por exemplo, caminhos de arquivo / diretório com mais de 260 caracteres).

Markus
fonte
0

A melhor resposta que posso encontrar está em um dos comentários aqui. Adicionando-o à resposta para que alguém não perca o comentário e com certeza tente fazer isso. Ele corrigiu o problema para mim.

Precisamos mapear a pasta de solução para uma unidade usando o comando "subst" no prompt de comando - por exemplo, subst z:

E então abra a solução desta unidade (z neste caso). Isso encurtaria o caminho o máximo possível e resolveria o problema de nomes de arquivo longos.

Jatin Nath Prusty
fonte
0

isso também pode ser a solução. Algumas vezes também ocorre quando você mantém seu projeto de desenvolvimento muito profundo, o que significa que pode ser possível que o diretório do projeto tenha muitos diretórios, portanto, não faça muitos diretórios mantê-lo em uma pasta simples dentro do unidades. Por exemplo - eu também estava recebendo este erro quando meu projeto foi mantido assim -

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

então simplesmente colei meu projeto dentro

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication

E o problema foi resolvido.

user3820036
fonte