วิธีที่ดีที่สุดในการแก้ไขเส้นทางไฟล์ข้อยกเว้นที่ยาวเกินไป


109

ฉันสร้างแอปที่ดาวน์โหลดไลบรารีเอกสารทั้งหมดในไซต์ SP แต่เมื่อถึงจุดหนึ่งมันทำให้ฉันมีข้อผิดพลาดนี้ (ฉันพยายามหาที่ google แต่ไม่พบสิ่งใดตอนนี้หากใครรู้เคล็ดลับในการแก้ปัญหานี้โปรดตอบกลับด้วยขอบคุณ สำหรับการดู)

System.IO.PathTooLongException: พา ธ ที่ระบุชื่อไฟล์หรือทั้งสองอย่างยาวเกินไป ชื่อไฟล์แบบเต็มต้องมีความยาวน้อยกว่า 260 อักขระและชื่อไดเร็กทอรีต้องน้อยกว่า 248 อักขระ ที่ System.IO.Path.NormalizePathFast (เส้นทางสตริงบูลีน fullCheck) ที่ System.IO.Path.GetFullPathInternal (เส้นทางสตริง) ที่ System.IO.FileStream.init (เส้นทางสตริงโหมด FileMode การเข้าถึง FileAccess สิทธิ์ Int32 บูลีน useRights , แชร์ FileShare, Int32 bufferSize, ตัวเลือก FileOptions, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy) ที่ System.IO.FileStream..ctor (เส้นทางสตริง, โหมด FileMode, การเข้าถึง FileAccess, การแชร์ FileShare, Int32 bufferSize, ตัวเลือก FileOptions) ที่ 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 [แปลงเป็นรูปแบบ 8.3 โดยใช้ CMD] [1] [1]: stackoverflow.com/questions/10227144/…
AutomationNation


อาจซ้ำกันได้ ที่นี่ฉันพบวิธีแก้ปัญหาstackoverflow.com/a/44211420/5312148
Francesco

คำตอบ:


58

เนื่องจากสาเหตุของข้อผิดพลาดนั้นชัดเจนนี่คือข้อมูลบางส่วนที่จะช่วยคุณแก้ปัญหา:

ดูบทความ MS นี้เกี่ยวกับการตั้งชื่อไฟล์เส้นทางและเนมสเปซ

นี่คือคำพูดจากลิงค์:

ขีดจำกัดความยาวเส้นทางสูงสุดใน Windows API (มีข้อยกเว้นบางประการที่กล่าวถึงในย่อหน้าต่อไปนี้) ความยาวสูงสุดสำหรับเส้นทางคือ MAX_PATH ซึ่งกำหนดเป็น 260 อักขระ โลคัลพา ธ มีโครงสร้างตามลำดับต่อไปนี้: อักษรชื่อไดรฟ์โคลอนแบ็กสแลชคอมโพเนนต์ชื่อที่คั่นด้วยแบ็กสแลชและอักขระว่างที่สิ้นสุด ตัวอย่างเช่นเส้นทางสูงสุดบนไดรฟ์ D คือ "D: \ some 256-character path string <NUL>" โดยที่ "<NUL>" แสดงถึงอักขระ null ที่สิ้นสุดที่มองไม่เห็นสำหรับหน้ารหัสหน้าระบบปัจจุบัน (อักขระ <> ถูกใช้ที่นี่เพื่อความชัดเจนของภาพและไม่สามารถเป็นส่วนหนึ่งของสตริงพา ธ ที่ถูกต้องได้)

และวิธีแก้ปัญหาเล็กน้อย (นำมาจากความคิดเห็น):

มีวิธีการแก้ปัญหาต่างๆ ความคิดพื้นฐานของการแก้ปัญหาที่ระบุไว้ด้านล่างเป็นแบบเดียวกันเสมอ: path-length + name-length < MAX_PATHลดเส้นทางที่ยาวเพื่อให้มี คุณสามารถ:

  • แชร์โฟลเดอร์ย่อย
  • ใช้บรรทัดคำสั่งเพื่อกำหนดอักษรระบุไดรฟ์โดยใช้ SUBST
  • ใช้ AddConnection ภายใต้ VB เพื่อกำหนดอักษรระบุไดรฟ์ให้กับเส้นทาง

7
@TimeToThine คุณอ่านบทความที่ฉันโพสต์หรือยัง? คุณอ่านความคิดเห็นหรือไม่? ฉันอาจจะคิดผิด แต่ฉันไม่คิดว่าคุณจะได้รับความช่วยเหลือจากชุมชน SO อีกแล้วนอกเหนือจากที่ฉันให้ไปแล้ว
James Hill

2
ใช่ฉันได้อ่านแล้วก่อนที่จะโพสต์คำถามของฉันที่นี่ฉันได้ลองใช้ "\\? \" ด้วยซ้ำ แต่ด้วยเหตุผลบางประการจึงไม่ทำงานในบริบทนี้ ฉันพบว่าบล็อกนี้ใช้งานได้ แต่ด้วยเหตุผลบางประการทำให้ " codinghorror.com/blog/2006/08/shortening-long-file-paths.html " ฉันยังคงมองหาสิ่งที่ช่วยให้บันทึกไดเรกทอรีอยู่และฉันสามารถทำได้ ใช้จากที่นั่นหรืออะไรทำนองนั้นตัวอย่าง forexample ใช้ป้ายกำกับที่ซ่อนอยู่เพื่อบันทึกไดเร็กทอรีปัจจุบันแทนสตริง แต่ไม่แน่ใจว่าจะใช้ได้หรือไม่
มูฮัมหมัดราชา

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 แล้ว แต่ยังคงได้รับข้อผิดพลาดไม่รู้ว่าทำไม ณ จุดนี้
Mr Angry

บทความกล่าวถึงข้อกำหนดสองประการ ประการแรกคีย์รีจิสทรีและประการที่สองแอ็พพลิเคชัน 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
Ondra Starenko

ดังที่กล่าวไว้ข้างต้นมันทำงานได้ดีใน Visual Studio 2019 (หลังจากรีสตาร์ท) โดยไม่ต้องเปลี่ยน xml ของแอปพลิเคชัน ขอบคุณสำหรับการแก้ปัญหา
Zoman

@ TomAnderson: ฉันใช้ VS2017 ฉันสามารถหา application.xml นี้ได้ที่ไหน หลังจากทำขั้นตอนที่ 1 แล้วไม่สามารถแก้ปัญหาของฉันได้
Sharad

24

มีห้องสมุดชื่อZeta Long Pathsที่ให้. NET API เพื่อทำงานกับเส้นทางยาว

นี่เป็นบทความดีๆที่ครอบคลุมปัญหานี้สำหรับทั้ง. NET และ PowerShell: " .NET, PowerShell Path too Long Exception และ. NET PowerShell Robocopy Clone "


1
ตอนนี้มันยอดเยี่ยมมากและง่ายมากในการอัปเดตโค้ดเพื่อใช้งาน ขอบคุณ.
Arthur

3

คุณสามารถสร้างลิงก์สัญลักษณ์ด้วยไดเร็กทอรีที่สั้นกว่า เปิดบรรทัดคำสั่งก่อนเช่นโดยShift + RightClickในโฟลเดอร์ที่คุณต้องการด้วยเส้นทางที่สั้นกว่า (คุณอาจต้องเรียกใช้ในฐานะผู้ดูแลระบบ)

จากนั้นพิมพ์ด้วยเส้นทางสัมพัทธ์หรือสัมบูรณ์:

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

จากนั้นเริ่มโซลูชันจากเส้นทางที่สั้นกว่า ข้อดีคือคุณไม่ต้องเคลื่อนย้ายอะไรเลย


สิ่งนี้ใช้ไม่ได้ใน VS2015 ดูเหมือนว่า VS กำลังประเมินความยาวของเส้นทางล่วงหน้า ดูคำตอบของ N-Ate สำหรับการแก้ไขปัญหา VS2015
N-ate

1
สิ่งที่คุณทำได้คือแมปโฟลเดอร์โซลูชันกับไดรเวอร์โดยใช้คำสั่ง "subst" ที่ใช้ได้กับ VS2017
Filipe Calasans

2

บน Windows 8.1 โดยใช้ไฟล์. NET 3.5 ฉันมีปัญหาที่คล้ายกัน
แม้ว่าชื่อไฟล์ของฉันมีความยาวเพียง 239 อักขระเมื่อฉันไปสร้างอินสแตนซ์อ็อบเจ็กต์ FileInfo ด้วยชื่อไฟล์ (ไม่มีพา ธ ) แต่เกิดข้อยกเว้นของประเภท 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 จะเหลือเพียง 20 อักขระสำหรับเส้นทางที่เหลือ (เช่น "c: \ temp") . หากคุณตัดแต่งชื่อไฟล์คุณต้องตรวจสอบให้แน่ใจว่าเส้นทางแบบเต็มมีอักขระไม่เกิน 259 ตัว
Losbear

1

หากคุณมีปัญหากับไฟล์binของคุณเนื่องจากเส้นทางที่ยาวใน Visual Studio 2015 คุณสามารถไปที่หน้าคุณสมบัติของโครงการที่กระทำผิดและเปลี่ยนไดเรกทอรีผลลัพธ์ที่สัมพันธ์กันให้สั้นลง

เช่นbin \ debug \กลายเป็นC: \ _ bins \ MyProject \


1
หลังจากเปิดคุณสมบัติอีกครั้งเมื่อบิวด์ของฉันล้มเหลวฉันสังเกตเห็นว่าเส้นทางใหม่"c: \ vs \ bin \ Release"ถูกแทนที่ด้วย".. \ .. \ .. \ .. \ .. \ .. \ .. \. . \ vs \ bin \ Release \ " . ฉันไม่แน่ใจว่า".. \"รวมอยู่ในจำนวนอักขระหรือไม่
มิส

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} ซึ่งอาจน้อยกว่าเส้นทางแบบเต็มของคุณที่ฉันหวังไว้มากสำหรับฉันฉันสามารถลดได้ถึง 30 อักขระจากประมาณ 290 อักขระ :)


0

ยังไม่ได้กล่าวถึงและการอัปเดตมีไลบรารีที่สร้างขึ้นเป็นอย่างดีสำหรับการจัดการเส้นทางที่ยาวเกินไป AlphaFSเป็นไลบรารี. NET ที่ให้การทำงานของระบบไฟล์ Win32 ที่สมบูรณ์ยิ่งขึ้นไปยังแพลตฟอร์ม. NET มากกว่าคลาส System.IO มาตรฐาน ข้อบกพร่องที่โดดเด่นที่สุดของ. NET System.IO มาตรฐานคือการขาดการสนับสนุนคุณสมบัติ NTFS ขั้นสูงการสนับสนุนพา ธ ความยาวที่เพิ่มขึ้นโดยเฉพาะอย่างยิ่ง (เช่นพา ธ ไฟล์ / ไดเร็กทอรีที่ยาวกว่า 260 อักขระ)


0

คำตอบที่ดีที่สุดที่ฉันสามารถหาได้อยู่ในหนึ่งในความคิดเห็นที่นี่ เพิ่มคำตอบเพื่อไม่ให้ใครพลาดความคิดเห็นและควรลองทำดู มันแก้ไขปัญหาให้ฉัน

เราจำเป็นต้องแม็พโฟลเดอร์โซลูชันกับไดรฟ์โดยใช้คำสั่ง "subst" ใน command prompt - เช่น subst z:

จากนั้นเปิดโซลูชันจากไดรฟ์นี้ (z ในกรณีนี้) วิธีนี้จะทำให้เส้นทางสั้นลงให้มากที่สุดและสามารถแก้ปัญหาชื่อไฟล์ที่ยาวได้


0

นี่อาจเป็นวิธีแก้ปัญหาบางครั้งยังเกิดขึ้นเมื่อคุณเก็บโปรเจ็กต์การพัฒนาของคุณไว้ลึกเกินไปหมายความว่าไดเร็กทอรีโปรเจ็กต์อาจเป็นไปได้อาจมีไดเร็กทอรีมากเกินไปดังนั้นโปรดอย่าสร้างไดเร็กทอรีมากเกินไปให้เก็บไว้ในโฟลเดอร์ง่ายๆภายใน ไดรฟ์ ตัวอย่างเช่นฉันได้รับข้อผิดพลาดนี้เมื่อโครงการของฉันถูกเก็บไว้เช่นนี้ -

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

จากนั้นฉันก็วางโครงการของฉันไว้ข้างใน

D: \ Sharad \ LatestWorkings \ GenericSurveyApplication

และปัญหาได้รับการแก้ไข

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.