ファイルパスが長すぎるという例外を解決する最良の方法


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共有、Int32 bufferSize、FileOptionsオプション、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(String path)

文字列の制限に達した場合、コードを以下に示します。

#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形式に変換します。:[1] [1]〜[CMDを使用して8.3形式に変換] stackoverflow.com/questions/10227144/...
AutomationNation


重複の可能性があります。ここで私はソリューションstackoverflow.com/a/44211420/5312148
フランチェスコ

回答:


58

エラーの原因は明らかなので、問題の解決に役立つ情報を以下に示します。

ファイル、パス、名前空間の命名に関するこのMS記事を参照してください。

ここにリンクからの引用があります:

パスの最大長の制限 Windows APIでは(次の段落で説明するいくつかの例外を除き)、パスの最大長はMAX_PATHであり、260文字として定義されています。ローカルパスは、ドライブ文字、コロン、バックスラッシュ、バックスラッシュで区切られた名前コンポーネント、終端のnull文字の順に構成されています。たとえば、ドライブDの最大パスは "D:\ some 256-character path string <NUL>"です。ここで、 "<NUL>"は現在のシステムコードページの非表示の終端null文字を表します。(文字<>はここでは視覚的にわかりやすくするために使用されており、有効なパス文字列の一部にすることはできません。)

そして、いくつかの回避策(コメントから取得):

さまざまな問題を解決する方法があります。下記に記載されているソリューションの基本的な考え方は常に同じです:持っているために、パスの長さを減らします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」アムはまだディレクトリが保存され、私ができる何かを探し続けますそこから取得するか、そのようなものを使用します。たとえば、文字列ではなく非表示のラベルを使用して現在のディレクトリを保存しますが、機能するかどうかは不明です。
ムハンマドラジャ

24
それは明らかですが、意味がありません。なぜパスサイズの制限があるのですか?それは2017
。– Jaider

2
Directory.SetCurrentDirectory()を使用して現在のディレクトリをフォルダーのディレクトリに変更した場合、この制限は回避されます。または、問題はまだ存在しますか。
アダムリンゼイ

3
記事は更新されたようStarting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions. です:しかし、オプトインして、レジストリキーを設定して有効にする必要があります。
トム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に設定してもエラーが発生しますが、現時点では理由がわかりません。
Angry氏、

この記事では2つの要件について述べています。1つ目はレジストリキー、2つ目はアプリケーションの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を再起動した後、この2番目の要件は必要ありませんでした。
トムアンダーソン

多分これは愚かな質問ですが、「アプリケーションxml」とは何ですか?それはweb.configか何かですか?私はWebページのasp.netプロジェクトでこの問題を抱えています
Ondra Starenko

上記のように、アプリケーションのxmlを変更せずにVisual Studio 2019(再起動後)で正常に動作します。解決策をありがとう。
ゾマン

@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で機能します。
フィリップカラサン

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の場合、残りのパスには20文字しか残りません(例: "c:\ temp") 。ファイル名をトリミングする場合は、フルパスが259文字以下であることを確認する必要があります。
Losbear

1

パスが長いためにbinファイルに問題がある場合、Visual Studio 2015では、問題のプロジェクトのプロパティページに移動して、相対出力ディレクトリをより短いものに変更できます。

たとえば、bin \ debug \C:\ _ bins \ MyProject \になります。


1
ビルドが失敗したときにプロパティを再度開いた後、新しいパス「c:\ vs \ bin \ Release」「.. \ .. \ .. \ .. \ .. \ .. \ .. \ に置き換えられていることに気付きました。 。\ vs \ bin \ Release \ "「.. \」が文字数に含まれるかどうかはわかりません。
samis

2
長すぎると評価されるパスは絶対パスです。
N-ate

1

私にとってうまくいったのは、プロジェクトがデスクトップ(C:\ Users \ lachezar.l \ Desktop \ MyFolder)にあるのと同じように(C:\ 0 \ MyFolder)に移動することです。問題。


1

私の経験から、一般向けWebアプリケーションについては、以下の回答はお勧めしません。

社内ツールやテストに必要な場合は、自分のマシンで共有することをお勧めします。

-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クラスよりも完全なWin32ファイルシステム機能を.NETプラットフォームに提供する.NETライブラリです。標準の.NET System.IOの最も顕著な欠点は、高度なNTFS機能のサポートが欠如していることです。特に、拡張パスのサポート(たとえば、260文字を超えるファイル/ディレクトリパス)はサポートされていません。


0

私が見つけることができる最良の答えは、ここのコメントの1つです。それを回答に追加して、誰かがコメントを見逃さないようにし、間違いなくこれを試してみてください。それは私のために問題を修正しました。

コマンドプロンプトで "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.