2011-05-25 18 views
5

इसलिए मैं एक प्रोग्राम लिख रहा हूं जो कंप्यूटर पर डुप्लिकेट फ़ाइलों के लिए स्कैन करेगा क्योंकि मैंने जो प्रोग्राम देखा है, वे वास्तव में धीमे हैं, और/या मेमोरी हॉग हैं, लेकिन जब मैं पूरे ड्राइव की कोशिश करता हूं तो मैं PathTooLongException में चला रहा था। PathTooLongException in C# code पढ़ने के बाद मैं निम्नलिखित दो प्रश्नों के बारे में उत्सुक हो गया।PathTooLongException को कैसे दूर करें?

  1. यदि मैं स्तर बदलता हूं तो क्या मैं अपनी वर्तमान निर्देशिका को स्विच करना चाहता हूं तो क्या यह मेरे प्रदर्शन को चोट पहुंचाएगा?

  2. क्या सभी फ़ाइलों की निर्देशिका संरचना प्राप्त करने का कोई बेहतर तरीका है (शायद पेड़.एक्सई जैसे कुछ कॉल करके और फिर उसे पार्स करना)?

+0

Downvoter देखभाल टिप्पणी करने के लिए एक बाहरी पुस्तकालय या पी का उपयोग किए बिना एक headstart दे देंगे लागू ..? – soandos

+0

पूरे फाइल सिस्टम स्कैन करने के लिए सबसे अच्छा अभ्यास व्यक्तिगत संदर्भ स्विच लगता है - .NET में, शायद यह एक नए धागे की तरह दिखने वाला है - कम से कम पहले स्तर के लिए यदि दूसरा या तीसरा नहीं है। यही है, प्रत्येक रूट फ़ोल्डर के लिए एक थ्रेड स्पिन करें, उस धागे में एक बार निर्देशिका बदलें, फिर आगे बढ़ें। यदि आप चालाक हैं, तो आप केवल तभी स्प्रेड कर सकते हैं जब पथ की लंबाई सीमा पार हो जाती है, फिर वहां निर्देशिका बदलें और प्रभावी ढंग से अपनी पथ की लंबाई सहिष्णुता को रीसेट करें। – ssamuel

+0

कैसे करें: एक निर्देशिका वृक्ष के माध्यम से Iterate (सी # प्रोग्रामिंग गाइड) http://msdn.microsoft.com/en-us/library/bb513869.aspx – JamieSee

उत्तर

3

इस लाइब्रेरी को देखें!

.NET Base Class Libraries : Long Path

+0

किम हैमिल्टन लॉन्ग पथ ब्लॉग सेरी भी बेहतर समझने के लिए एक लायक है मुद्दा: http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx – AFract

1

या यह अपने आप करते हैं,

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Runtime.InteropServices; 
using Microsoft.Win32.SafeHandles; 

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
internal static extern IntPtr FindFirstFile(string lpFileName, out 
           WIN32_FIND_DATA lpFindFileData); 

[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
internal static extern bool FindNextFile(IntPtr hFindFile, out 
           WIN32_FIND_DATA lpFindFileData); 

[DllImport("kernel32.dll", SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
internal static extern bool FindClose(IntPtr hFindFile); 

// Assume dirName passed in is already prefixed with \\?\ 
public static IEnumerable<string> EnumerateEntries(string directory) 
{ 
    WIN32_FIND_DATA findData; 
    IntPtr findHandle = FindFirstFile(dirName + @"\*", out findData); 

    try 
    { 
     if (findHandle != INVALID_HANDLE_VALUE) 
     { 
      bool found; 
      do 
      { 
       string currentFileName = findData.cFileName; 

       // if this is a directory, find its contents 
       if (((int)findData.dwFileAttributes & 
           FILE_ATTRIBUTE_DIRECTORY) != 0) 
       { 
        if (currentFileName != "." && currentFileName != "..") 
        { 
         foreach(var child in FindFilesAndDirs(
           Path.Combine(dirName, currentFileName)) 
         { 
          yield return child; 
         } 
        } 
       } 

       yield return Path.Combine(dirName, currentFileName); 

       // find next 
       found = FindNextFile(findHandle, out findData); 
      } 
      while (found); 
     } 

    } 
    finally 
    { 
     // close the find handle 
     FindClose(findHandle); 
    } 
} 

मैं इस कोड सत्यापित नहीं किया है और स्पष्ट रूप से नहीं सभी प्रकार परिभाषित कर रहे हैं, लेकिन यह सही दिशा में हमें इंगित करना चाहिए।

0

शुद्ध सी #, अनुकूलन की जरूरत है, लेकिन लोग/

public static class DirectoryEx 
{ 
    static char driveLetter; 
    static string longPath; 
    static List<string> directories; 

    static DirectoryEx() 
    { 
     longPath = String.Empty; 
    } 

    private static char GetAvailableDrive() 
    { 
     var all = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().Reverse(); 
     var occupied = DriveInfo.GetDrives() 
      .OrderByDescending(d => d.Name) 
      .Select(d => (char)d.Name.ToUpper().First()); 

     var free = all.Except(occupied).First(); 

     return free; 
    } 

    public static List<string> GetDirectories(string path) 
    { 
     directories = new List<string>(); 

     // recursive call 
     FindDirectories(path); 

     return directories; 
    } 

    static void FindDirectories(string path) 
    { 
     try 
     { 
      foreach (var directory in Directory.GetDirectories(path)) 
      { 
       var di = new DirectoryInfo(directory); 

       if(!String.IsNullOrEmpty(longPath)) 
        directories.Add(di.FullName.Replace(driveLetter + ":\\", longPath + "\\")); 
       else 
        directories.Add(di.FullName); 

       FindDirectories(di.FullName); 
      } 
     } 
     catch (UnauthorizedAccessException uaex) { Debug.WriteLine(uaex.Message); } 
     catch (PathTooLongException ptlex) 
     { 
      Debug.WriteLine(ptlex.Message); 

      longPath = path; 

      Task t = new Task(new Action(() => 
      { 
       CreateVirtualDrive(longPath); 
       FindDirectories(driveLetter + ":\\"); 
       DeleteVirtualDrive(); 

       longPath = String.Empty; 
      })); 

      if (!String.IsNullOrEmpty(longPath)) 
       t.RunSynchronously(); 
     } 
     catch (Exception ex) 
     { 
      Debug.WriteLine(ex.Message); 
     } 
    } 

    static void CreateVirtualDrive(string path) 
    { 
     driveLetter = GetAvailableDrive(); 

     Process.Start(new ProcessStartInfo() { 
      FileName = "cmd.exe", 
      WindowStyle = ProcessWindowStyle.Hidden, 
      Arguments = String.Format("/c subst {0}: {1}", driveLetter.ToString(), path) 
     }); 

     while (!DriveInfo.GetDrives().Select(d => d.Name.ToUpper().First()).Contains(driveLetter)) 
     { 
      System.Threading.Thread.Sleep(1); 
     } 
    } 

    static void DeleteVirtualDrive() 
    { 
     Process.Start(new ProcessStartInfo() 
     { 
      FileName = "cmd.exe", 
      WindowStyle = ProcessWindowStyle.Hidden, 
      Arguments = String.Format("/c subst {0}: /D", driveLetter.ToString()) 
     }); 

     while (DriveInfo.GetDrives().Select(d => d.Name.ToUpper().First()).Contains(driveLetter)) 
     { 
      System.Threading.Thread.Sleep(1); 
     } 
    } 
}