如何克服PathTooLongException
本文关键字:PathTooLongException 克服 何克服 | 更新日期: 2023-09-27 17:57:40
因此,我正在编写一个程序,该程序将扫描计算机上的重复文件,因为我看到的程序非常慢,和/或占用内存,但当我尝试整个驱动器时,遇到了PathTooLongException
。在阅读了C#代码中的PathTooLongException之后,我对以下两个问题感到好奇。
-
如果每次更改级别时都切换当前目录,会不会影响我的性能?
-
有没有更好的方法来获取所有文件的目录结构(也许可以调用tree.exe之类的东西,然后对其进行解析)?
查看此库!
.NET Base Class Libraries : Long Path
或者自己动手,
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);
}
}
我还没有验证这个代码,显然不是所有的类型都定义好了,但它应该为我们指明正确的方向。
Pure 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);
}
}
}