La mejor manera de resolver la ruta del archivo es una excepción demasiado larga

109

Creé una aplicación que descarga todas las bibliotecas de documentos en un sitio SP, pero en un momento me dio este error (intenté buscar en Google pero no pude encontrar nada, ahora si alguien conoce algún truco para resolver este problema, responda de lo contrario gracias por mirarlo)

System.IO.PathTooLongException: la ruta especificada, el nombre de archivo o ambos son demasiado largos. El nombre de archivo completo debe tener menos de 260 caracteres y el nombre del directorio debe tener menos de 248 caracteres. en System.IO.Path.NormalizePathFast (ruta de cadena, booleano fullCheck) en System.IO.Path.GetFullPathInternal (ruta de cadena) en System.IO.FileStream.Init (ruta de cadena, modo FileMode, acceso a FileAccess, derechos Int32, useRights booleanos , Recurso compartido de FileShare, Int32 bufferSize, opciones de FileOptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) en System.IO.FileStream..ctor (ruta de cadena, modo FileMode, acceso a FileAccess, recurso compartido de FileShare, Int32 bufferSize, opciones de FileOptions) en System. IO.File.Create (ruta de la cadena)

alcanza el límite de cadena, el código se da a continuación,

#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
fuente
1
Convierta la ruta UNC (o lo que sea) en un formato 8.3. [Convertir a formato 8.3 usando CMD] [1] [1]: stackoverflow.com/questions/10227144/…
AutomationNation
¿Posible duplicado de Cómo evitar System.IO.PathTooLongException?
Deantwo
Posible duplicado. Aquí descubrí la solución stackoverflow.com/a/44211420/5312148
Francesco

Respuestas:

58

Como la causa del error es obvia, aquí hay información que debería ayudarlo a resolver el problema:

Consulte este artículo de MS sobre nombres de archivos, rutas y espacios de nombres

Aquí hay una cita del enlace:

Limitación de la longitud máxima de la ruta En la API de Windows (con algunas excepciones que se describen en los siguientes párrafos), la longitud máxima de una ruta es MAX_PATH, que se define como 260 caracteres. Una ruta local se estructura en el siguiente orden: letra de unidad, dos puntos, barra invertida, componentes de nombre separados por barras invertidas y un carácter nulo final. Por ejemplo, la ruta máxima en la unidad D es "D: \ alguna cadena de ruta de 256 caracteres <NUL>" donde "<NUL>" representa el carácter nulo de terminación invisible para la página de códigos del sistema actual. (Los caracteres <> se utilizan aquí para mayor claridad visual y no pueden formar parte de una cadena de ruta válida).

Y algunas soluciones alternativas (tomadas de los comentarios):

Hay formas de resolver los distintos problemas. La idea básica de las soluciones enumeradas a continuación es siempre la misma: Reducir la longitud de la ruta para tener path-length + name-length < MAX_PATH. Puedes:

  • Comparte una subcarpeta
  • Utilice la línea de comandos para asignar una letra de unidad mediante SUBST
  • Use AddConnection en VB para asignar una letra de unidad a una ruta
James Hill
fuente
7
@TimeToThine, ¿leíste el artículo que publiqué? ¿Leíste los comentarios? Podría estar equivocado, pero no creo que vayas a recibir más ayuda de la comunidad SO, aparte de la que ya he proporcionado.
James Hill
2
Sí, ya leí eso antes de publicar mi pregunta aquí, incluso intenté "\\? \" Pero por alguna razón no funciona en este contexto. Encuentro este blog, utilizándolo pero por alguna razón no funciona correctamente, " codinghorror.com/blog/2006/08/shortening-long-file-paths.html " Todavía estoy buscando algo que mantenga el directorio guardado y puedo tómelo desde allí, o algo así, por ejemplo, use una etiqueta oculta para guardar el directorio actual en lugar de la cadena, pero no estoy seguro de si funcionará.
Muhammad Raja
24
Es obvio pero no tiene ningún sentido. ¿Por qué hay una limitación en el tamaño de la ruta? es 2017.
Jaider
2
Si cambiara el directorio actual al directorio de la carpeta usando Directory.SetCurrentDirectory (), evitaría esta restricción. ¿O el problema aún existiría?
Adam Lindsay
3
El artículo parece haber sido actualizado: Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. pero debe optar por participar y establecer una clave de registro para habilitarlo.
Tom Deblauwe
28

La solución que funcionó para mí fue editar la clave de registro para habilitar el comportamiento de ruta larga, estableciendo el valor en 1. Esta es una nueva función de suscripción para Windows 10

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

Obtuve esta solución de una sección con nombre del artículo que publicó @ james-hill.

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

goonerify
fuente
2
Tengo este conjunto en 1 y sigo recibiendo el error, no tengo idea de por qué en este momento.
Mr Angry
El artículo menciona dos requisitos. En primer lugar, la clave de registro y, en segundo lugar, la aplicación xml: <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 mí, en Visual Studio 2019, este segundo requisito no era necesario después de reiniciar Visual Studio.
Tom Anderson
Lo siento, probablemente esta es una pregunta estúpida, pero ¿Qué es "xml de aplicación"? ¿Es web.config o algo más? Tengo este problema en el proyecto de página web asp.net
Ondra Starenko
Como se dijo anteriormente, funciona bien en Visual Studio 2019 (después de reiniciar) sin cambiar el xml de la aplicación. Gracias por la solucion
Zoman
@TomAnderson: Estoy usando VS2017. ¿Dónde puedo encontrar este archivo application.xml? ya que después de hacer el primer paso no resuelve mi problema.
Sharad
3

Puede crear un enlace simbólico con un directorio más corto. Primero abra la línea de comando, por ejemplo, Shift + RightClicken la carpeta deseada con una ruta más corta (es posible que deba ejecutarla como administrador).

Luego escriba con rutas relativas o absolutas:

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

Y luego inicie la Solución desde el camino más corto. La ventaja aquí es: no tienes que mover nada.

Markus Weber
fuente
Esto no funciona en VS2015. Parece que VS está prevalidando la longitud de la ruta. Consulte la respuesta N-Ate para la solución alternativa de VS2015.
N-ate el
1
Lo que puede hacer es asignar la carpeta de la solución a un controlador usando el comando "subst". Eso funciona para VS2017.
Filipe Calasans
2

En Windows 8.1, usando. NET 3.5, tuve un problema similar.
Aunque el nombre de mi archivo tenía solo 239 caracteres de longitud, cuando fui a crear una instancia de un objeto FileInfo con solo el nombre del archivo (sin ruta), se produjo una excepción del 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

Resolví el problema recortando el nombre del archivo a 204 caracteres (extensión incluida).

Marcel Piquet
fuente
Información adicional para cualquiera que lea esto: los nombres de archivo están limitados a 247 caracteres mientras que la ruta completa está limitada a 259. Por lo tanto, si su nombre de archivo es 239, eso solo deja 20 caracteres para el resto de la ruta (por ejemplo, "c: \ temp") . Si recorta el nombre del archivo, debe asegurarse de que la ruta COMPLETA tenga 259 caracteres o menos.
Losbear
1

Si tiene un problema con sus archivos bin debido a una ruta larga, en Visual Studio 2015 puede ir a la página de propiedades del proyecto infractor y cambiar el directorio de salida relativo a uno más corto.

Por ejemplo, bin \ debug \ se convierte en C: \ _ bins \ MyProject \

N-ate
fuente
1
Después de volver a abrir las propiedades cuando mi compilación falló, noté que la nueva ruta "c: \ vs \ bin \ Release" se sustituyó por ".. \ .. \ .. \ .. \ .. \ .. \ .. \. . \ vs \ bin \ Release \ " . No estoy seguro de si ".. \" se incluye en el recuento de caracteres.
samis
2
Las rutas que se evalúan como demasiado largas son rutas absolutas.
N-ate el
1

Lo que funcionó para mí es mover mi proyecto tal como estaba en el escritorio (C: \ Users \ lachezar.l \ Desktop \ MyFolder) a (C: \ 0 \ MyFolder) que, como puede ver, usa una ruta más corta y, al reducirla, resolvió el problema.

Lachezar Lalov
fuente
1

Desde mi experiencia, no recomendaré mi respuesta a continuación para ninguna aplicación web pública.

Si lo necesita para sus herramientas internas o para pruebas, le recomendaría compartirlo en su propia 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

Esto luego creará un directorio compartido como \\ {PCName} \ {YourSharedRootDirectory} Esto podría ser definitivamente mucho menor que su ruta completa, espero, para mí podría reducir a 30 caracteres de aproximadamente 290 caracteres. :)

Riyaz Hameed
fuente
0

Sin mencionar hasta ahora y una actualización, hay una biblioteca muy bien establecida para manejar rutas que son demasiado largas. AlphaFS es una biblioteca .NET que proporciona una funcionalidad de sistema de archivos Win32 más completa para la plataforma .NET que las clases estándar System.IO. La deficiencia más notable del estándar .NET System.IO es la falta de compatibilidad con las funciones avanzadas de NTFS, sobre todo la compatibilidad con rutas de longitud extendida (por ejemplo, rutas de archivo / directorio de más de 260 caracteres).

Markus
fuente
0

La mejor respuesta que puedo encontrar, está en uno de los comentarios aquí. Agregarlo a la respuesta para que alguien no se pierda el comentario y definitivamente debería probar esto. Me solucionó el problema.

Necesitamos mapear la carpeta de la solución a una unidad usando el comando "subst" en el símbolo del sistema, por ejemplo, subst z:

Y luego abra la solución desde esta unidad (z en este caso). Esto acortaría la ruta tanto como fuera posible y podría resolver el largo problema del nombre de archivo.

Jatin Nath Prusty
fuente
0

Esto también puede ser una posible solución.A veces también ocurre cuando mantiene su proyecto de desarrollo demasiado profundo, lo que significa que puede ser posible que el directorio del proyecto tenga demasiados directorios, así que no haga demasiados directorios, manténgalo en una carpeta simple dentro del unidades. Por ejemplo, también recibí este error cuando mi proyecto se mantuvo así-

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

luego simplemente pegué mi proyecto dentro

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication

Y el problema se resolvió.

user3820036
fuente