2012-03-06 113 views
3

我在.NET 4.0中使用DirectoryInfo和FileInfo來枚舉目錄樹中的文件,並且遇到PathTooLongException。簡化版本低於從PathTooLongException中檢索路徑信息

public static class Test 
{ 
    public static void Search(DirectoryInfo base) 
    { 
     foreach(var file in base.GetFiles()) 
     { 
      try 
      { 
       Console.WriteLine(file.FullName); 
      } catch(PathTooLongException ex) 
      { 
       // What path was this? 
      } 
     } 
     foreach(var dir in base.GetDirectories()) 
     { 
      Search(dir); 
     } 
    } 
} 

當拋出的錯誤,我想知道是什麼文件路徑導致的問題。顯然,我不能要求FullName,因爲這是錯誤的。我可以從file.Name得到名字,但是如果我無法得到路徑的其餘部分,因爲file.Directory給出PathTooLongException,即使DirectoryInfo該文件被發現工作正常! (我不能使用它,因爲實際代碼要複雜得多)。

通過堆棧跟蹤看起來,它似乎正在使用一個內部路徑(我看到從調試保護file.FullPath),並試圖從完整(超大)的路徑撕裂目錄。大部分問題似乎涉及System.IO.Path.NormalizePath,我聽說在.Net 4.0中經歷了一些變化。我還沒有嘗試過這個框架的以前的版本。

我的問題:

  1. 我怎樣才能得到這個異常的完整路徑;它似乎通過了沒有任何有用的信息。
  2. 爲什麼框架需要限制路徑中的字符來切斷文件名?

在此先感謝您的幫助,
安迪

回答

6

我想不出任何其他方式又比使用反射,或使用圖書館或P/Invoke來使用其他我的頭頂支持長路徑並手動檢查長度的Windows API。完整路徑存儲在protected string場稱爲FullPath

foreach(var dir in new DirectoryInfo (@"D:\longpaths") 
        .GetFileSystemInfos("*.*", SearchOption.AllDirectories)) 
{ 
    try 
    { 
     Console.WriteLine(dir.FullName); 
    } 
    catch (PathTooLongException) 
    { 
       FieldInfo fld = typeof(FileSystemInfo).GetField(
             "FullPath", 
             BindingFlags.Instance | 
             BindingFlags.NonPublic); 
       Console.WriteLine(fld.GetValue(dir)); // outputs your long path 
    } 
} 

如果你想實際上做文件的東西,不能只檢查文件的長度,我建議使用一個圖書館這樣一個from the BCL team at Microsoft,但它不會創建DirectoryInfosFileInfoFileSystemInfo,只能是字符串。所以它可能不是你的代碼的替代品。

至於你的第二個問題的答案,我建議閱讀處理.NET中的長路徑的this blog post。這是引用它的原因,它解釋了爲什麼他們沒有快速地在.NET中添加長路徑支持。

很少有人抱怨32K限制,所以問題解決了嗎?不完全的。有幾個原因,我們過去不願意添加長路徑,以及爲什麼我們仍然對此保持謹慎,這與安全性,\ API語法中的Windows API的不一致支持以及應用程序兼容性有關。

這是一個由3部分組成的系列文章,解釋了爲什麼API是這種方式以及爲什麼限制在那裏的幾個原因。

+0

謝謝克里斯託弗,我擔心情況會如此。只是私下保留路徑並且不允許在沒有先驗證它的情況下訪問它,儘管它爲我創建了無效路徑就好了。 您指向的'LongPath'庫看起來很棒!不幸的是,我忘了提及所有路徑都是UNC,因此無法按原樣使用(還)。通過代碼來查看如何實現直接API會非常有用。 – Andyrooger 2012-03-07 09:49:35

+0

@Andyrooger,是的,我忘了那個。我分叉了代碼,並在不久前添加了該代碼。你可以在codeplex項目中獲得代碼(http://longpaths.codeplex.com/)。使用源代碼,而不是發行版,我修復了一個愚蠢的錯誤。 – 2012-03-07 21:01:29

+0

@ChristopherCurrens +1 FieldInfo提示! – 2013-06-11 19:09:31