Najlepszy sposób na rozwiązanie wyjątku zbyt długiej ścieżki pliku

109

Stworzyłem aplikację, która pobiera wszystkie biblioteki dokumentów ze strony SP, ale w pewnym momencie daje mi ten błąd (próbowałem spojrzeć na Google, ale nie mogłem nic znaleźć, teraz jeśli ktoś zna jakąś sztuczkę, aby rozwiązać ten problem, odpowiedz inaczej, dziękuję za obejrzenie tego)

System.IO.PathTooLongException: określona ścieżka, nazwa pliku lub obie są za długie. W pełni kwalifikowana nazwa pliku musi mieć mniej niż 260 znaków, a nazwa katalogu musi mieć mniej niż 248 znaków. w System.IO.Path.NormalizePathFast (ścieżka String, Boolean fullCheck) w System.IO.Path.GetFullPathInternal (ścieżka String) w System.IO.FileStream.Init (ścieżka ciągu, tryb FileMode, dostęp do pliku, prawa Int32, prawa do użycia logicznego , FileShare share, Int32 bufferSize, opcje FileOptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) w System.IO.FileStream..ctor (ścieżka String, tryb FileMode, dostęp do FileAccess, udział FileShare, Int32 bufferSize, opcje FileOptions) w System. IO.File.Create (ścieżka ciągu)

osiąga limit dla ciągu, kod podano poniżej,

#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
źródło
1
Konwertuj ścieżkę UNC (lub jakąkolwiek inną) na format 8.3. [Konwertuj do formatu 8.3 przy użyciu CMD] [1] [1]: stackoverflow.com/questions/10227144/ ...
AutomationNation
Możliwy duplikat. Tutaj znalazłem rozwiązanie stackoverflow.com/a/44211420/5312148
Francesco,

Odpowiedzi:

58

Ponieważ przyczyna błędu jest oczywista, oto kilka informacji, które powinny pomóc w rozwiązaniu problemu:

Zobacz ten artykuł MS na temat nazewnictwa plików, ścieżek i przestrzeni nazw

Oto cytat z linku:

Ograniczenie maksymalnej długości ścieżki W interfejsie API systemu Windows (z pewnymi wyjątkami omówionymi w kolejnych akapitach) maksymalna długość ścieżki wynosi MAX_PATH, która jest zdefiniowana jako 260 znaków. Ścieżka lokalna ma następującą kolejność: litera dysku, dwukropek, ukośnik odwrotny, składniki nazwy oddzielone ukośnikami odwrotnymi i kończący znak null. Na przykład maksymalna ścieżka na dysku D to „D: \ jakiś 256-znakowy ciąg ścieżki <NUL>”, gdzie „<NUL>” reprezentuje niewidoczny kończący znak zerowy dla bieżącej strony kodowej systemu. (Znaki <> są tutaj używane dla przejrzystości wizualnej i nie mogą być częścią prawidłowego ciągu ścieżki).

I kilka obejść (zaczerpniętych z komentarzy):

Istnieją sposoby rozwiązania różnych problemów. Podstawowa idea rozwiązań wymienionych poniżej jest zawsze taka sama: Zmniejsz długość ścieżki, aby mieć path-length + name-length < MAX_PATH. Możesz:

  • Udostępnij podfolder
  • Użyj wiersza poleceń, aby przypisać literę dysku za pomocą SUBST
  • Użyj AddConnection w VB, aby przypisać literę dysku do ścieżki
James Hill
źródło
7
@TimeToThine, czy przeczytałeś artykuł, który opublikowałem? Czy przeczytałeś komentarze? Mogę się mylić, ale nie sądzę, abyś uzyskał więcej pomocy od społeczności SO poza tym, co już zapewniłem.
James Hill,
2
Tak, już przeczytałem, że przed wysłaniem tutaj mojego pytania próbowałem nawet „\\? \”, Ale z jakiegoś powodu nie działa w tym kontekście. Uważam, że ten blog jest używany, ale z jakiegoś powodu nie działa poprawnie, " codinghorror.com/blog/2006/08/shortening-long-file-paths.html " Wciąż szukam czegoś, co zachowa zapisany katalog i mogę weź to stamtąd lub coś w tym rodzaju, na przykład użyj ukrytej etykiety, aby zapisać bieżący katalog zamiast łańcucha, ale nie jesteś pewien, czy to zadziała.
Muhammad Raja,
24
To oczywiste, ale bez sensu. Dlaczego istnieje ograniczenie rozmiaru ścieżki ??? jest 2017.
Jaider
2
Gdybym zmienił bieżący katalog na katalog folderu przy użyciu Directory.SetCurrentDirectory (), pozwoliłoby to uniknąć tego ograniczenia. A może problem nadal istniał.
Adam Lindsay
3
Wygląda na to, że artykuł został zaktualizowany: Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. ale musisz wyrazić zgodę i ustawić klucz rejestru, aby go włączyć.
Tom Deblauwe,
28

Rozwiązaniem, które działało dla mnie, była edycja klucza rejestru, aby umożliwić zachowanie długiej ścieżki, ustawiając wartość na 1. Jest to nowa funkcja opt-in dla systemu Windows 10

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

Mam to rozwiązanie z nazwanej sekcji artykułu, który opublikował @ james-hill.

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

goonerify
źródło
2
Mam to ustawione na 1 i nadal otrzymuję błąd, nie mam pojęcia, dlaczego w tym momencie.
Mr Angry
Artykuł wspomina o dwóch wymaganiach. Po pierwsze klucz rejestru, a po drugie xml aplikacji: <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>dla mnie w Visual Studio 2019 to drugie wymaganie nie było konieczne po ponownym uruchomieniu Visual Studio.
Tom Anderson
Przepraszam, prawdopodobnie to głupie pytanie, ale co to jest „XML aplikacji”? Czy to jest web.config czy coś innego? Mam ten problem na stronie WWW projektu asp.net
Ondra Starenko
Jak wspomniano powyżej, działa dobrze w Visual Studio 2019 (po ponownym uruchomieniu) bez zmiany XML aplikacji. Dzięki za rozwiązanie.
Zoman
@TomAnderson: Używam VS2017. Gdzie mogę znaleźć ten plik application.xml? jak po wykonaniu 1 kroku nie rozwiązuje mojego problemu.
Sharad
3

Możesz utworzyć dowiązanie symboliczne z krótszym katalogiem. Najpierw otwórz wiersz poleceń, na przykład Shift + RightClickw wybranym folderze z krótszą ścieżką (może być konieczne uruchomienie go jako administrator).

Następnie wpisz ze ścieżkami względnymi lub bezwzględnymi:

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

A następnie zacznij Rozwiązanie od krótszej ścieżki. Zaleta jest taka: nie musisz niczego przenosić.

Markus Weber
źródło
To nie działa w VS2015. Wydawałoby się, że VS wstępnie weryfikuje długość ścieżki. Zobacz odpowiedź N-Ate na obejście problemu VS2015.
Zjadłem
1
Możesz zmapować folder rozwiązania na sterownik za pomocą polecenia „subst”. To działa w przypadku VS2017.
Filipe Calasans
2

W systemie Windows 8.1 za pomocą. NET 3.5, miałem podobny problem.
Chociaż nazwa mojego pliku miała tylko 239 znaków długości, kiedy poszedłem do utworzenia wystąpienia obiektu FileInfo z samą nazwą pliku (bez ścieżki), wystąpił wyjątek typu 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

Rozwiązałem problem, skracając nazwę pliku do 204 znaków (łącznie z rozszerzeniem).

Marcel Piquet
źródło
Dodatkowe informacje dla każdego, kto to czyta - nazwy plików są ograniczone do 247 znaków, a pełna ścieżka jest ograniczona do 259. Jeśli więc nazwa pliku to 239, pozostawia to tylko 20 znaków w pozostałej części ścieżki (np. „C: \ temp”) . Jeśli przycinasz nazwę pliku, upewnij się, że PEŁNA ścieżka ma 259 znaków lub mniej.
Losbear
1

Jeśli masz problem z plikami bin z powodu długiej ścieżki, w programie Visual Studio 2015 możesz przejść do strony właściwości projektu i zmienić względny katalog wyjściowy na krótszy.

Np. Bin \ debug \ staje się C: \ _ bins \ MyProject \

Zjadł
źródło
1
Po ponownym otwarciu właściwości, gdy moja kompilacja się nie powiodła, zauważyłem, że nowa ścieżka „c: \ vs \ bin \ Release” została zastąpiona jako „.. \ .. \ .. \ .. \ .. \ .. \ .. \. . \ vs \ bin \ Release \ " . Nie jestem pewien, czy ".. \" zostanie uwzględnione w liczbie znaków.
samis
2
Ścieżki oceniane jako zbyt długie są ścieżkami bezwzględnymi.
N-zjadł
1

Udało mi się przenieść projekt tak, jak był na pulpicie (C: \ Users \ lachezar.l \ Desktop \ MyFolder) do (C: \ 0 \ MyFolder), co, jak widać, używa krótszej ścieżki i zmniejszenie go rozwiązało problem.

Lachezar Lalov
źródło
1

Z mojego doświadczenia nie polecam mojej poniższej odpowiedzi dla żadnych publicznych aplikacji internetowych.

Jeśli potrzebujesz go do własnych narzędzi lub do testowania, polecam udostępnienie go na własnym komputerze.

-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

Spowoduje to utworzenie katalogu współdzielonego, takiego jak \\ {PCName} \ {YourSharedRootDirectory}. Może to być zdecydowanie mniej niż pełna ścieżka, mam nadzieję, dla mnie mógłbym zmniejszyć do 30 znaków z około 290 znaków. :)

Riyaz Hameed
źródło
0

Jak dotąd nie wspominając o aktualizacji, istnieje bardzo dobrze rozwinięta biblioteka do obsługi zbyt długich ścieżek. AlphaFS to biblioteka .NET zapewniająca pełniejszą funkcjonalność systemu plików Win32 na platformie .NET niż standardowe klasy System.IO. Najbardziej zauważalną wadą standardowego .NET System.IO jest brak obsługi zaawansowanych funkcji NTFS, w szczególności obsługi rozszerzonych ścieżek (np. Ścieżki do plików / katalogów dłuższe niż 260 znaków).

Markus
źródło
0

Najlepsza odpowiedź, jaką mogę znaleźć, znajduje się w jednym z komentarzy tutaj. Dodanie go do odpowiedzi, aby ktoś nie przegapił komentarza i zdecydowanie powinien to wypróbować. Rozwiązało to dla mnie problem.

Musimy zmapować folder rozwiązania na dysk za pomocą polecenia „subst” w wierszu polecenia - np. Subst z:

A następnie otwórz rozwiązanie z tego dysku (w tym przypadku z). Skróciłoby to ścieżkę tak bardzo, jak to możliwe i mogłoby rozwiązać długi problem z nazwą pliku.

Jatin Nath Prusty
źródło
0

może to być również możliwe rozwiązanie. Czasami zdarza się również, gdy trzymasz projekt deweloperski zbyt głęboko, co oznacza, że ​​może być możliwe, że katalog projektu może zawierać zbyt wiele katalogów, więc nie twórz zbyt wielu katalogów, przechowuj go w prostym folderze wewnątrz dyski. Na przykład - otrzymałem również ten błąd, gdy mój projekt był przechowywany w ten sposób-

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

potem po prostu wkleiłem mój projekt do środka

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication

I problem został rozwiązany.

user3820036
źródło