파일 경로가 너무 긴 예외를 해결하는 가장 좋은 방법


109

SP 사이트에서 모든 문서 라이브러리를 다운로드하는 앱을 만들었지 만 한 번에이 오류가 발생했습니다 (Google을 보려고했지만 아무것도 찾을 수 없었습니다. 이제이 문제를 해결하는 트릭을 아는 사람이 있으면 그렇지 않으면 응답 해주세요. 그것을보고)

System.IO.PathTooLongException : 지정된 경로, 파일 이름 또는 둘 다 너무 깁니다. 완전한 파일 이름은 260 자 미만이어야하며 디렉토리 이름은 248 자 미만이어야합니다. System.IO.Path.NormalizePathFast (String path, Boolean fullCheck) at System.IO.Path.GetFullPathInternal (String path) at System.IO.FileStream.Init (String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights , FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) at System.IO.FileStream..ctor (String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options) at System. IO.File.Create (문자열 경로)

문자열 한도에 도달하면 코드는 아래와 같습니다.

#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

1
UNC (또는 기타) 경로를 8.3 형식으로 변환합니다. [CMD를 사용하여 8.3 형식으로 변환] [1] [1] : stackoverflow.com/questions/10227144/…
AutomationNation


중복 가능성. 여기에서 솔루션을 찾았습니다. stackoverflow.com/a/44211420/5312148
Francesco

답변:


58

오류의 원인은 분명하므로 문제 해결에 도움이되는 몇 가지 정보는 다음과 같습니다.

파일, 경로 및 네임 스페이스 이름 지정에 대한MS 문서를 참조하십시오.

다음은 링크의 인용문입니다.

최대 경로 길이 제한 Windows API (다음 단락에서 설명하는 일부 예외 포함)에서 경로의 최대 길이는 260 자로 정의되는 MAX_PATH입니다. 로컬 경로는 드라이브 문자, 콜론, 백 슬래시, 백 슬래시로 구분 된 이름 구성 요소 및 종료 널 문자의 순서로 구성됩니다. 예를 들어, D 드라이브의 최대 경로는 "D : \ some 256 자 경로 문자열 <NUL>"입니다. 여기서 "<NUL>"은 현재 시스템 코드 페이지에 대해 보이지 않는 종료 널 문자를 나타냅니다. (여기서 <> 문자는 시각적 명확성을 위해 사용되며 유효한 경로 문자열의 일부가 될 수 없습니다.)

그리고 몇 가지 해결 방법 (댓글에서 가져옴) :

다양한 문제를 해결하는 방법이 있습니다. 아래 나열된 솔루션의 기본 아이디어는 항상 동일 path-length + name-length < MAX_PATH합니다.. 당신은 할 수있다:

  • 하위 폴더 공유
  • 명령 줄을 사용하여 SUBST를 통해 드라이브 문자를 할당합니다.
  • VB에서 AddConnection을 사용하여 경로에 드라이브 문자를 할당합니다.

7
@TimeToThine, 내가 게시 한 기사를 읽었습니까? 댓글을 읽었습니까? 내가 틀릴 수도 있지만, 내가 이미 제공 한 것 외에는 SO 커뮤니티에서 더 이상 도움을받을 수 없을 것이라고 생각합니다.
James Hill

2
예, 여기에 내 질문을 게시하기 전에 이미 "\\? \"를 시도했지만 어떤 이유로이 컨텍스트에서는 작동하지 않습니다. 이 블로그를 사용하고 있지만 어떤 이유로 제대로 작동하지 않는 것을 발견했습니다. " codinghorror.com/blog/2006/08/shortening-long-file-paths.html "여전히 디렉토리를 저장할 수있는 무언가를 찾고 있습니다. 예를 들어 문자열 대신 현재 디렉토리를 저장하기 위해 숨겨진 레이블을 사용하지만 작동할지 여부는 확실하지 않습니다.
Muhammad Raja

24
분명하지만 말이되지 않습니다. 경로 크기 제한이있는 이유는 무엇입니까 ??? 그것은 2017 년이다
Jaider

2
Directory.SetCurrentDirectory ()를 사용하여 현재 디렉토리를 폴더의 디렉토리로 변경하면 이러한 제한을 피할 수 있습니다. 아니면 문제가 여전히 존재합니까?
Adam Lindsay

3
기사가 업데이트 된 것 같습니다. Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. 그러나 옵트 인하고 활성화하려면 레지스트리 키를 설정해야합니다.
Tom Deblauwe

28

나를 위해 일한 솔루션은 긴 경로 동작을 사용하도록 레지스트리 키를 편집하여 값을 1로 설정하는 것이 었습니다. 이것은 Windows 10의 새로운 옵트 인 기능입니다.

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

이 솔루션은 @ james-hill이 게시 한 기사의 명명 된 섹션에서 얻었습니다.

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


2
나는 이것을 1로 설정했지만 여전히 오류가 발생합니다.이 시점에서 이유를 모릅니다.
미스터 화가

이 기사에서는 두 가지 요구 사항을 언급합니다. 첫 번째는 레지스트리 키이고 두 번째는 애플리케이션 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>Visual Studio 2019에서는 Visual Studio를 다시 시작한 후에이 두 번째 요구 사항이 필요하지 않았습니다.
Tom Anderson

아마 이것은 어리석은 질문이지만 "application xml"은 무엇입니까? web.config 또는 다른 것입니까? 나는 웹 페이지 asp.net 프로젝트에서이 문제가
온 드라 Starenko

위에서 말했듯이 응용 프로그램 xml을 변경하지 않고 Visual Studio 2019 (다시 시작한 후)에서 제대로 작동합니다. 솔루션에 감사드립니다.
Zoman

@TomAnderson : VS2017을 사용하고 있습니다. 이 application.xml은 어디에서 찾을 수 있습니까? 첫 번째 단계를 수행해도 문제가 해결되지 않습니다.
Sharad


3

더 짧은 디렉토리로 심볼릭 링크를 만들 수 있습니다. 예를 들어 경로가 더 짧은 원하는 폴더에서 먼저 명령 줄엽니 다Shift + RightClick (관리자 권한으로 실행해야 할 수 있음).

그런 다음 상대 또는 절대 경로로 입력합니다.

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

그런 다음 더 짧은 경로에서 솔루션을 시작하십시오. 여기에서 장점은 : 아무것도 이동할 필요가 없다는 것입니다.


이것은 VS2015에서 작동하지 않습니다. VS가 경로의 길이를 사전 검증하는 것처럼 보입니다. VS2015 해결 방법에 대한 N-Ate 답변을 참조하십시오.
N-ate

1
할 수있는 일은 "subst"명령을 사용하여 솔루션 폴더를 드라이버에 매핑하는 것입니다. VS2017에서 작동합니다.
Filipe Calasans 2010 년

2

Windows 8.1에서. NET 3.5에서도 비슷한 문제가 발생했습니다.
파일 이름 (경로 없음)만으로 FileInfo 개체를 인스턴스화하려고했을 때 내 파일 이름이 239 자에 불과했지만 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

파일 이름을 204 자 (확장자 포함)로 자르는 문제를 해결했습니다.


이 글을 읽는 사람을위한 추가 정보-파일 이름은 247 자로 제한되고 전체 경로는 259로 제한됩니다. 따라서 파일 이름이 239 인 경우 나머지 경로 (예 : "c : \ temp")에 20 자만 남습니다. . 파일 이름을 다듬는 경우 전체 경로가 259 자 이하인지 확인해야합니다.
Losbear

1

긴 경로로 인해 bin 파일에 문제가있는 경우 Visual Studio 2015에서 문제가되는 프로젝트의 속성 페이지로 이동하여 상대 출력 디렉터리 를 더 짧은 디렉터리 로 변경할 수 있습니다 .

예 : bin \ debug \C : \ _ bins \ MyProject \가됩니다.


1
빌드가 실패했을 때 속성을 다시 연 후 새 경로 "c : \ vs \ bin \ Release"".. \ .. \ .. \ .. \ .. \ .. \ .. \ 로 대체되었습니다 . . \ \ 빈 \ 릴리스 \ "대 . ".. \" 이 문자 수에 포함 되는지 확실하지 않습니다 .
samis

2
너무 긴 것으로 평가되는 경로는 절대 경로입니다.
N-ate

1

나를 위해 일한 것은 데스크탑 (C : \ Users \ lachezar.l \ Desktop \ MyFolder)에 있던 내 프로젝트를 (C : \ 0 \ MyFolder)로 옮기는 것입니다. 문제.


1

내 경험으로 볼 때 공개 웹 응용 프로그램에 대해 아래 답변을 권장하지 않습니다.

사내 도구 또는 테스트에 필요한 경우 자신의 컴퓨터에서 공유하는 것이 좋습니다.

-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

그러면 \\ {PCName} \ {YourSharedRootDirectory}와 같은 공유 디렉토리가 생성됩니다. 이것은 내가 바라는 전체 경로보다 훨씬 적을 수 있습니다. 약 290 자에서 30 자로 줄일 수 있습니다. :)


0

지금까지 언급하지 않았고 업데이트가 너무 긴 경로를 처리하기위한 매우 잘 설정된 라이브러리가 있습니다. AlphaFS 는 표준 System.IO 클래스보다 .NET 플랫폼에보다 완전한 Win32 파일 시스템 기능을 제공하는 .NET 라이브러리입니다. 표준 .NET System.IO의 가장 두드러진 결함은 고급 NTFS 기능, 특히 확장 된 길이 경로 지원 (예 : 260 자보다 긴 파일 / 디렉토리 경로)이 지원되지 않는다는 것입니다.


0

내가 찾을 수있는 가장 좋은 대답은 여기 댓글 중 하나입니다. 누군가가 댓글을 놓치지 않고 확실히 시도해 볼 수 있도록 답변에 추가하십시오. 그것은 나를 위해 문제를 해결했습니다.

명령 프롬프트에서 "subst"명령을 사용하여 솔루션 폴더를 드라이브에 매핑해야합니다 (예 : subst z :

그런 다음이 드라이브에서 솔루션을 엽니 다 (이 경우 z). 이렇게하면 경로가 최대한 짧아지고 긴 파일 이름 문제를 해결할 수 있습니다.


0

이것은 또한 해결책이 될 수 있습니다. 개발 프로젝트를 너무 깊게 보관할 때도 발생합니다. 프로젝트 디렉토리에 디렉토리가 너무 많을 수 있으므로 너무 많은 디렉토리를 만들지 마십시오. 드라이브. 예를 들어-내 프로젝트가 다음과 같이 유지되었을 때도이 오류가 발생했습니다.

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

그런 다음 단순히 프로젝트를 내부에 붙여 넣었습니다.

D : \ Sharad \ LatestWorkings \ GenericSurveyApplication

그리고 문제가 해결되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.