C# 长度超过248字符的路径或文件的查找
昨天帮同事写了一个查找文件的小工具, 却发现弹出了这个错误信息:The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. 大概的意思就是:指定的路径或文件名太长,或者两者都太长。完全限定文件名必须少于 260 个字符,并且目录名必须少于 248 个字符。用.NET的类库或API的findfirst\findnext都解决不了这个问题.
在MSDN上关于路径和文件的命名规则, 长度和\\?\前缀的文档:
http://msdn2.microsoft.com/en-us/library/aa365247.aspx
于是用API的findfirstfile/findnextfile重写了那个索引的函数(下载请点此处)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Windows.Forms;
namespace FileExplorer
{
class FindApiClass
{
internal const int MAX_PATH = 260;
internal static int INVALID_HANDLE_VALUE = -1;
internal static int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
public int iFileSize = 0;
[StructLayout(LayoutKind.Sequential)]
internal struct FILETIME
{
internal uint dwLowDateTime;
internal uint dwHighDateTime;
}
[DllImport("kernel32.dll", EntryPoint = "FindFirstFileA")]
private static extern int FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", EntryPoint = "FindNextFileA")]
private static extern bool FindNextFile(int hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", EntryPoint = "FindClose")]
private static extern bool FindClose(int hFindFile);
public static List<string[]> SearchFiles(string dirName, string ExtMask)
{
List<string[]> results = new List<string[]>();
WIN32_FIND_DATA findData;
dirName = dirName.Replace(@"\\",@"\");
int findHandle = FindFirstFile(dirName + ExtMask, out findData);
//搜索文件
Boolean found = true;
string currentFileName = "";
do
{
currentFileName = findData.cFileName;
if (currentFileName != "." && currentFileName != "..")
{
if ((findData.dwFileAttributes != 0) && (findData.dwFileAttributes != 16) && (findData.dwFileAttributes != 18)
&& (findData.dwFileAttributes != 22) && (findData.dwFileAttributes != 48) && (findData.dwFileAttributes != 8208))
{
string[] arrSubItem = new string[4];
arrSubItem[0] = Path.Combine(dirName, currentFileName);
arrSubItem[1] = Convert.ToString(findData.nFileSizeLow - findData.nFileSizeHigh);
arrSubItem[2] = GetFileExt(currentFileName);
long hFT2 = (((long)findData.ftLastWriteTime.dwHighDateTime) << 32) + (long)findData.ftLastWriteTime.dwLowDateTime;
DateTime dt = DateTime.FromFileTimeUtc(hFT2).AddHours(8);
arrSubItem[3] = dt.ToString("yyyy-MM-dd HH:mm:ss");
results.Add(arrSubItem);
}
}
// find next
found = FindNextFile(findHandle, out findData);
}
while (found);
FindClose(findHandle);
//搜索子目录
findHandle = FindFirstFile(dirName + "*", out findData);
//Boolean found = true;
do
{
currentFileName = findData.cFileName;
if (currentFileName != "." && currentFileName != ".." && currentFileName != "")
{
if ((findData.dwFileAttributes == 0) || (findData.dwFileAttributes == 16) || (findData.dwFileAttributes == 18)
|| (findData.dwFileAttributes == 22) || (findData.dwFileAttributes == 48) || (findData.dwFileAttributes == 8208))
{
List<string[]> childResults = SearchFiles(Path.Combine(dirName, currentFileName + @"\"), ExtMask);
// add children and self to results
results.AddRange(childResults);
}
}
// find next
found = FindNextFile(findHandle, out findData);
}
while (found);
FindClose(findHandle);
return results;
}
private static int GetFileSize(int size)
{
int results = 0;
if (size >= 1024)
{
if ((size % 1024) > 0)
results = (size / 1024 + 1);
else
results = (size / 1024);
}
else
{
results = 1;
}
return results;
}
private static string GetFileExt(string FileName)
{
if (FileName.IndexOf(".") > 0)
{
string str = FileName.Substring(FileName.IndexOf(".") + 1, FileName.Length - FileName.IndexOf(".") - 1);
if (str.IndexOf(".") > 0)
str = GetFileExt(str);
return str;
}
else
{
return "";
}
}
[StructLayout(LayoutKind.Sequential)]
private struct WIN32_FIND_DATA
{
internal int dwFileAttributes;
internal FILETIME ftCreationTime;
internal FILETIME ftLastAccessTime;
internal FILETIME ftLastWriteTime;
internal int nFileSizeHigh;
internal int nFileSizeLow;
internal int dwReserved0;
internal int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
internal string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
internal string cAlternate;
}
}
}