因此,我正在編寫一個程序,用於掃描計算機上的重複文件,因爲我看過的程序非常慢,並且/或者內存耗盡,但是當我嘗試整個驅動器時遇到了PathTooLongException
。在閱讀PathTooLongException in C# code後,我對以下兩個問題感到好奇。如何克服PathTooLongException?
如果我每次更改關卡時切換當前目錄,會傷害我的表現嗎?
有沒有更好的方式來獲得所有文件的目錄結構(也許通過調用像tree.exe然後解析)?
因此,我正在編寫一個程序,用於掃描計算機上的重複文件,因爲我看過的程序非常慢,並且/或者內存耗盡,但是當我嘗試整個驅動器時遇到了PathTooLongException
。在閱讀PathTooLongException in C# code後,我對以下兩個問題感到好奇。如何克服PathTooLongException?
如果我每次更改關卡時切換當前目錄,會傷害我的表現嗎?
有沒有更好的方式來獲得所有文件的目錄結構(也許通過調用像tree.exe然後解析)?
The Kim Hamilton Long Path博客系列也值得一看,以便更好地理解問題:http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx – AFract 2014-11-18 15:18:08
或自己做,
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);
}
}
我還沒有證實此代碼,顯然不是所有的類型定義,但它應該爲我們指出了正確的方向。
純C#,需要進行優化,但會給人一種領先地位,而無需使用外部庫或P /調用..
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);
}
}
}
Downvoter照顧對此有何評論? – soandos 2011-05-27 14:01:28
掃描整個文件系統的最佳實踐似乎是單獨的上下文切換 - 在.NET中,這可能看起來像一個新的線程 - 至少在第一個級別,如果不是第二個甚至第三個。也就是說,爲每個根文件夾旋轉一個線程,在該線程中更改一次目錄,然後繼續。如果你很聰明,只有在路徑長度超過閾值時才能自適應地旋轉線程,然後在那裏改變目錄並有效地重置路徑長度容差。 – ssamuel 2011-08-26 13:29:44
如何:通過目錄樹迭代(C#編程指南) http://msdn.microsoft.com/en-us/library/bb513869.aspx – JamieSee 2011-12-27 23:25:30