이름이 259 자보다 긴 파일을 처리하는 방법은 무엇입니까?
일부 디렉토리의 모든 파일을 살펴보고 해당 파일에 대해 몇 가지 작업을 수행하는 응용 프로그램에서 작업 중입니다. 무엇보다도 파일 크기와이 파일이 수정 된 날짜를 검색해야합니다.
너무 오래되고 일부 파일 전체 이름 (디렉토리 + 파일 이름), I는 .NET 프레임 워크 사용할 수없는 FileInfo
제한됩니다, MAX_PATH
(260 자). 많은 웹 소스는 이름이 너무 긴 파일에 액세스하기 위해 P / Invoke를 통해 기본 Win32 기능을 사용하도록 권장했습니다.
현재 Win32 기능에서도 똑같은 문제가 발생하는 것 같습니다. 예를 들어, GetFileAttributesEx
(kernel32.dll)은 270 바이트 경로에 대해 Win32 오류 3 ERROR_PATH_NOT_FOUND와 함께 실패합니다.
Notepad2에서 동일한 파일을 성공적으로 열고 Windows 탐색기에 성공적으로 표시 할 수 있습니다 (그러나 Visual Studio 2010은 259 자 제한 ¹으로 인해 파일을 열지 못함).
파일 경로가 270 자일 때 파일에 액세스하려면 어떻게해야합니까?
메모:
파일 경로 길이가 259자를 초과하는 파일을 제거하거나 무시하는 것은 해결책이 아닙니다.
유니 코드 호환 솔루션 만 찾고 있습니다.
이 응용 프로그램은 .NET Framework 4가 설치된 Windows 2008 / Vista 이상에서 실행됩니다.
¹ 놀랍게도 Microsoft Word 2007이 실패하여 플로피 드라이브가없는 컴퓨터에서 "플로피 디스크가 너무 작습니다"또는 4GB의 RAM이 남아있을 때 "RAM 메모리가 부족합니다"라고 불평합니다. "바이러스 백신 소프트웨어 [...]를 업데이트해야합니다." 언젠가는 마이크로 소프트 오피스와 같은 주요 제품에서 그런 어리석은 의미없는 오류를 표시하는 것을 멈출까요?
.NET 4.6.2 솔루션
여기에\\?\C:\Verrrrrrrrrrrry long path
설명 된 구문을 사용 하십시오 .
.NET Core 솔루션
프레임 워크가 긴 경로 구문을 추가하기 때문에 작동합니다.
.NET 4.6.2 이전 솔루션
또한 P / Invoke와 함께 긴 경로 구문 과 Win32 API 함수의 유니 코드 버전을 사용하십시오. 에서 파일, 경로 및 네임 스페이스 명명 :
Windows API에는 최대 총 경로 길이가 32,767자인 확장 길이 경로를 허용하는 유니 코드 버전도있는 많은 함수가 있습니다. 이 유형의 경로는 각각 GetVolumeInformation 함수의 lpMaximumComponentLength 매개 변수에 반환 된 값까지 백 슬래시로 구분 된 구성 요소로 구성됩니다 (이 값은 일반적으로 255 자). 확장 길이 경로를 지정하려면
\\?\
접두사를 사용하십시오 . 예 :\\?\D:\very long path
.
이 Microsoft 지원 페이지를 읽는 것도 흥미로울 수 있습니다.
BCL 팀 블로그의 Kim Hamilton이 .NET의 Long Paths에 대한 매우 광범위한 설명 에는 이러한 경로를 처리하는 데 몇 가지 장애가 나열되어 있는데, 이것이이 구문이 여전히 .NET에서 직접 지원되지 않는 이유입니다.
우리가 과거에 긴 경로를 추가하기를 꺼려했던 몇 가지 이유와 우리가 여전히 그것에 대해주의하는 이유가 있습니다 <...>.
<...>
\\?\
접두사는 긴 경로를 활성화 할뿐만 아니라; Windows API에 의한 최소한의 수정으로 경로가 파일 시스템에 전달되도록합니다. 결과적으로\\?\
후행 공백 제거, '.'확장을 포함하여 Windows API에서 수행하는 파일 이름 정규화를 해제합니다. 및 '..', 상대 경로를 전체 경로로 변환하는 등. <...><...>
\\?\
접두사가있는 긴 경로 는 대부분의 파일 관련 Windows API에서 사용할 수 있지만 모든 Windows API는 사용할 수 없습니다. 예를 들어, 파일 이름이 MAX_PATH보다 길면 LoadLibrary <...>가 실패합니다. <...> Windows API 전체에 유사한 예가 있습니다. 일부 해결 방법이 있지만 사례별로 적용됩니다.또 다른 요소 <...>는 다른 Windows 기반 응용 프로그램 및 Windows 셸 자체 <...>와의 호환성입니다.
이 문제가 점점 보편화되고 있기 때문에 <...> Microsoft 전체에서이 문제를 해결하기위한 노력이 있습니다. 사실 적시에 Vista 플러그를 사용하면 MAX_PATH 제한에 도달 할 가능성을 줄이는 몇 가지 변경 사항을 확인할 수 있습니다. 많은 특수 폴더 이름이 단축되었으며 더 흥미롭게도 쉘은 자동 경로 축소 기능을 사용하고 있습니다. <...>을 사용하여 260 자로 압축합니다.
경고 : .NET Framework가 이러한 종류의 경로 구문을 지원하지 않을 수 있다고 생각하므로 Windows API를 직접 호출해야 할 수도 있습니다.
긴 파일 이름 문제를 극복하기 위해 Microsoft TechNet의 .NET Framework 4 기반 라이브러리 인 Delimon 라이브러리를 사용해 볼 수 있습니다.
Delimon.Win32.I O 라이브러리 (V4.0).
System.IO의 키 메서드 자체 버전이 있습니다. 예를 들어 다음을 대체합니다.
System.IO.Directory.GetFiles
와
Delimon.Win32.IO.Directory.GetFiles
긴 파일과 폴더를 처리 할 수 있습니다.
웹 사이트에서 :
Delimon.Win32.IO는 System.IO의 기본 파일 기능을 대체하며 최대 32,767 자까지 파일 및 폴더 이름을 지원합니다.
이 라이브러리는 .NET Framework 4.0에서 작성되었으며 x86 및 x64 시스템에서 사용할 수 있습니다. 표준 System.IO 네임 스페이스의 파일 및 폴더 제한은 파일 이름이 260 자이고 폴더 이름이 240자인 파일에서 작동 할 수 있습니다 (MAX_PATH는 일반적으로 260 자로 구성됨). 일반적으로 표준 .NET 라이브러리 에서 System.IO.PathTooLongException 오류가 발생합니다.
나는 그 문제를 해결하기 위해 내 자신 LongFile
과 LongDirectory
수업을 만들었습니다 . 평소에 사용할 때마다 사용 System.IO.File
합니다.
최적화 등이있을 수 있지만 몇 년 동안 잘 작동하고 있습니다.
public static class LongFile
{
private const int MAX_PATH = 260;
public static bool Exists(string path)
{
if (path.Length < MAX_PATH) return System.IO.File.Exists(path);
var attr = NativeMethods.GetFileAttributesW(GetWin32LongPath(path));
return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_ARCHIVE) == NativeMethods.FILE_ATTRIBUTE_ARCHIVE));
}
public static void Delete(string path)
{
if (path.Length < MAX_PATH) System.IO.File.Delete(path);
else
{
bool ok = NativeMethods.DeleteFileW(GetWin32LongPath(path));
if (!ok) ThrowWin32Exception();
}
}
public static void AppendAllText(string path, string contents)
{
AppendAllText(path, contents, Encoding.Default);
}
public static void AppendAllText(string path, string contents, Encoding encoding)
{
if (path.Length < MAX_PATH)
{
System.IO.File.AppendAllText(path, contents, encoding);
}
else
{
var fileHandle = CreateFileForAppend(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
{
var bytes = encoding.GetBytes(contents);
fs.Position = fs.Length;
fs.Write(bytes, 0, bytes.Length);
}
}
}
public static void WriteAllText(string path, string contents)
{
WriteAllText(path, contents, Encoding.Default);
}
public static void WriteAllText(string path, string contents, Encoding encoding)
{
if (path.Length < MAX_PATH)
{
System.IO.File.WriteAllText(path, contents, encoding);
}
else
{
var fileHandle = CreateFileForWrite(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
{
var bytes = encoding.GetBytes(contents);
fs.Write(bytes, 0, bytes.Length);
}
}
}
public static void WriteAllBytes(string path, byte[] bytes)
{
if (path.Length < MAX_PATH)
{
System.IO.File.WriteAllBytes(path, bytes);
}
else
{
var fileHandle = CreateFileForWrite(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Write))
{
fs.Write(bytes, 0, bytes.Length);
}
}
}
public static void Copy(string sourceFileName, string destFileName)
{
Copy(sourceFileName, destFileName, false);
}
public static void Copy(string sourceFileName, string destFileName, bool overwrite)
{
if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Copy(sourceFileName, destFileName, overwrite);
else
{
var ok = NativeMethods.CopyFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName), !overwrite);
if (!ok) ThrowWin32Exception();
}
}
public static void Move(string sourceFileName, string destFileName)
{
if (sourceFileName.Length < MAX_PATH && (destFileName.Length < MAX_PATH)) System.IO.File.Move(sourceFileName, destFileName);
else
{
var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceFileName), GetWin32LongPath(destFileName));
if (!ok) ThrowWin32Exception();
}
}
public static string ReadAllText(string path)
{
return ReadAllText(path, Encoding.Default);
}
public static string ReadAllText(string path, Encoding encoding)
{
if (path.Length < MAX_PATH) { return System.IO.File.ReadAllText(path, encoding); }
var fileHandle = GetFileHandle(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
{
var data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
return encoding.GetString(data);
}
}
public static string[] ReadAllLines(string path)
{
return ReadAllLines(path, Encoding.Default);
}
public static string[] ReadAllLines(string path, Encoding encoding)
{
if (path.Length < MAX_PATH) { return System.IO.File.ReadAllLines(path, encoding); }
var fileHandle = GetFileHandle(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
{
var data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
var str = encoding.GetString(data);
if (str.Contains("\r")) return str.Split(new[] { "\r\n" }, StringSplitOptions.None);
return str.Split('\n');
}
}
public static byte[] ReadAllBytes(string path)
{
if (path.Length < MAX_PATH) return System.IO.File.ReadAllBytes(path);
var fileHandle = GetFileHandle(GetWin32LongPath(path));
using (var fs = new System.IO.FileStream(fileHandle, System.IO.FileAccess.Read))
{
var data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
return data;
}
}
public static void SetAttributes(string path, FileAttributes attributes)
{
if (path.Length < MAX_PATH)
{
System.IO.File.SetAttributes(path, attributes);
}
else
{
var longFilename = GetWin32LongPath(path);
NativeMethods.SetFileAttributesW(longFilename, (int)attributes);
}
}
#region Helper methods
private static SafeFileHandle CreateFileForWrite(string filename)
{
if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_ALWAYS, 0, IntPtr.Zero);
if (hfile.IsInvalid) ThrowWin32Exception();
return hfile;
}
private static SafeFileHandle CreateFileForAppend(string filename)
{
if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.CREATE_NEW, 0, IntPtr.Zero);
if (hfile.IsInvalid)
{
hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_WRITE, NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
if (hfile.IsInvalid) ThrowWin32Exception();
}
return hfile;
}
internal static SafeFileHandle GetFileHandle(string filename)
{
if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
if (hfile.IsInvalid) ThrowWin32Exception();
return hfile;
}
internal static SafeFileHandle GetFileHandleWithWrite(string filename)
{
if (filename.Length >= MAX_PATH) filename = GetWin32LongPath(filename);
SafeFileHandle hfile = NativeMethods.CreateFile(filename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
if (hfile.IsInvalid) ThrowWin32Exception();
return hfile;
}
public static System.IO.FileStream GetFileStream(string filename, FileAccess access = FileAccess.Read)
{
var longFilename = GetWin32LongPath(filename);
SafeFileHandle hfile;
if (access == FileAccess.Write)
{
hfile = NativeMethods.CreateFile(longFilename, (int)(NativeMethods.FILE_GENERIC_READ | NativeMethods.FILE_GENERIC_WRITE | NativeMethods.FILE_WRITE_ATTRIBUTES), NativeMethods.FILE_SHARE_NONE, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
}
else
{
hfile = NativeMethods.CreateFile(longFilename, (int)NativeMethods.FILE_GENERIC_READ, NativeMethods.FILE_SHARE_READ, IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero);
}
if (hfile.IsInvalid) ThrowWin32Exception();
return new System.IO.FileStream(hfile, access);
}
[DebuggerStepThrough]
public static void ThrowWin32Exception()
{
int code = Marshal.GetLastWin32Error();
if (code != 0)
{
throw new System.ComponentModel.Win32Exception(code);
}
}
public static string GetWin32LongPath(string path)
{
if (path.StartsWith(@"\\?\")) return path;
if (path.StartsWith("\\"))
{
path = @"\\?\UNC\" + path.Substring(2);
}
else if (path.Contains(":"))
{
path = @"\\?\" + path;
}
else
{
var currdir = Environment.CurrentDirectory;
path = Combine(currdir, path);
while (path.Contains("\\.\\")) path = path.Replace("\\.\\", "\\");
path = @"\\?\" + path;
}
return path.TrimEnd('.'); ;
}
private static string Combine(string path1, string path2)
{
return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.'); ;
}
#endregion
public static void SetCreationTime(string path, DateTime creationTime)
{
long cTime = 0;
long aTime = 0;
long wTime = 0;
using (var handle = GetFileHandleWithWrite(path))
{
NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
var fileTime = creationTime.ToFileTimeUtc();
if (!NativeMethods.SetFileTime(handle, ref fileTime, ref aTime, ref wTime))
{
throw new Win32Exception();
}
}
}
public static void SetLastAccessTime(string path, DateTime lastAccessTime)
{
long cTime = 0;
long aTime = 0;
long wTime = 0;
using (var handle = GetFileHandleWithWrite(path))
{
NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
var fileTime = lastAccessTime.ToFileTimeUtc();
if (!NativeMethods.SetFileTime(handle, ref cTime, ref fileTime, ref wTime))
{
throw new Win32Exception();
}
}
}
public static void SetLastWriteTime(string path, DateTime lastWriteTime)
{
long cTime = 0;
long aTime = 0;
long wTime = 0;
using (var handle = GetFileHandleWithWrite(path))
{
NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
var fileTime = lastWriteTime.ToFileTimeUtc();
if (!NativeMethods.SetFileTime(handle, ref cTime, ref aTime, ref fileTime))
{
throw new Win32Exception();
}
}
}
public static DateTime GetLastWriteTime(string path)
{
long cTime = 0;
long aTime = 0;
long wTime = 0;
using (var handle = GetFileHandleWithWrite(path))
{
NativeMethods.GetFileTime(handle, ref cTime, ref aTime, ref wTime);
return DateTime.FromFileTimeUtc(wTime);
}
}
}
그리고 해당 LongDirectory
:
public class LongDirectory
{
private const int MAX_PATH = 260;
public static void CreateDirectory(string path)
{
if (string.IsNullOrWhiteSpace(path)) return;
if (path.Length < MAX_PATH)
{
System.IO.Directory.CreateDirectory(path);
}
else
{
var paths = GetAllPathsFromPath(GetWin32LongPath(path));
foreach (var item in paths)
{
if (!LongExists(item))
{
var ok = NativeMethods.CreateDirectory(item, IntPtr.Zero);
if (!ok)
{
ThrowWin32Exception();
}
}
}
}
}
public static void Delete(string path)
{
Delete(path, false);
}
public static void Delete(string path, bool recursive)
{
if (path.Length < MAX_PATH && !recursive)
{
System.IO.Directory.Delete(path, false);
}
else
{
if (!recursive)
{
bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(path));
if (!ok) ThrowWin32Exception();
}
else
{
DeleteDirectories(new string[] { GetWin32LongPath(path) });
}
}
}
private static void DeleteDirectories(string[] directories)
{
foreach (string directory in directories)
{
string[] files = LongDirectory.GetFiles(directory, null, System.IO.SearchOption.TopDirectoryOnly);
foreach (string file in files)
{
LongFile.Delete(file);
}
directories = LongDirectory.GetDirectories(directory, null, System.IO.SearchOption.TopDirectoryOnly);
DeleteDirectories(directories);
bool ok = NativeMethods.RemoveDirectory(GetWin32LongPath(directory));
if (!ok) ThrowWin32Exception();
}
}
public static bool Exists(string path)
{
if (path.Length < MAX_PATH) return System.IO.Directory.Exists(path);
return LongExists(GetWin32LongPath(path));
}
private static bool LongExists(string path)
{
var attr = NativeMethods.GetFileAttributesW(path);
return (attr != NativeMethods.INVALID_FILE_ATTRIBUTES && ((attr & NativeMethods.FILE_ATTRIBUTE_DIRECTORY) == NativeMethods.FILE_ATTRIBUTE_DIRECTORY));
}
public static string[] GetDirectories(string path)
{
return GetDirectories(path, null, SearchOption.TopDirectoryOnly);
}
public static string[] GetDirectories(string path, string searchPattern)
{
return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
}
public static string[] GetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption)
{
searchPattern = searchPattern ?? "*";
var dirs = new List<string>();
InternalGetDirectories(path, searchPattern, searchOption, ref dirs);
return dirs.ToArray();
}
private static void InternalGetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption, ref List<string> dirs)
{
NativeMethods.WIN32_FIND_DATA findData;
IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(path), searchPattern), out findData);
try
{
if (findHandle != new IntPtr(-1))
{
do
{
if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) != 0)
{
if (findData.cFileName != "." && findData.cFileName != "..")
{
string subdirectory = System.IO.Path.Combine(path, findData.cFileName);
dirs.Add(GetCleanPath(subdirectory));
if (searchOption == SearchOption.AllDirectories)
{
InternalGetDirectories(subdirectory, searchPattern, searchOption, ref dirs);
}
}
}
} while (NativeMethods.FindNextFile(findHandle, out findData));
NativeMethods.FindClose(findHandle);
}
else
{
ThrowWin32Exception();
}
}
catch (Exception)
{
NativeMethods.FindClose(findHandle);
throw;
}
}
public static string[] GetFiles(string path)
{
return GetFiles(path, null, SearchOption.TopDirectoryOnly);
}
public static string[] GetFiles(string path, string searchPattern)
{
return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
}
public static string[] GetFiles(string path, string searchPattern, System.IO.SearchOption searchOption)
{
searchPattern = searchPattern ?? "*";
var files = new List<string>();
var dirs = new List<string> { path };
if (searchOption == SearchOption.AllDirectories)
{
//Add all the subpaths
dirs.AddRange(LongDirectory.GetDirectories(path, null, SearchOption.AllDirectories));
}
foreach (var dir in dirs)
{
NativeMethods.WIN32_FIND_DATA findData;
IntPtr findHandle = NativeMethods.FindFirstFile(System.IO.Path.Combine(GetWin32LongPath(dir), searchPattern), out findData);
try
{
if (findHandle != new IntPtr(-1))
{
do
{
if ((findData.dwFileAttributes & System.IO.FileAttributes.Directory) == 0)
{
string filename = System.IO.Path.Combine(dir, findData.cFileName);
files.Add(GetCleanPath(filename));
}
} while (NativeMethods.FindNextFile(findHandle, out findData));
NativeMethods.FindClose(findHandle);
}
}
catch (Exception)
{
NativeMethods.FindClose(findHandle);
throw;
}
}
return files.ToArray();
}
public static void Move(string sourceDirName, string destDirName)
{
if (sourceDirName.Length < MAX_PATH || destDirName.Length < MAX_PATH)
{
System.IO.Directory.Move(sourceDirName, destDirName);
}
else
{
var ok = NativeMethods.MoveFileW(GetWin32LongPath(sourceDirName), GetWin32LongPath(destDirName));
if (!ok) ThrowWin32Exception();
}
}
#region Helper methods
[DebuggerStepThrough]
public static void ThrowWin32Exception()
{
int code = Marshal.GetLastWin32Error();
if (code != 0)
{
throw new System.ComponentModel.Win32Exception(code);
}
}
public static string GetWin32LongPath(string path)
{
if (path.StartsWith(@"\\?\")) return path;
var newpath = path;
if (newpath.StartsWith("\\"))
{
newpath = @"\\?\UNC\" + newpath.Substring(2);
}
else if (newpath.Contains(":"))
{
newpath = @"\\?\" + newpath;
}
else
{
var currdir = Environment.CurrentDirectory;
newpath = Combine(currdir, newpath);
while (newpath.Contains("\\.\\")) newpath = newpath.Replace("\\.\\", "\\");
newpath = @"\\?\" + newpath;
}
return newpath.TrimEnd('.');
}
private static string GetCleanPath(string path)
{
if (path.StartsWith(@"\\?\UNC\")) return @"\\" + path.Substring(8);
if (path.StartsWith(@"\\?\")) return path.Substring(4);
return path;
}
private static List<string> GetAllPathsFromPath(string path)
{
bool unc = false;
var prefix = @"\\?\";
if (path.StartsWith(prefix + @"UNC\"))
{
prefix += @"UNC\";
unc = true;
}
var split = path.Split('\\');
int i = unc ? 6 : 4;
var list = new List<string>();
var txt = "";
for (int a = 0; a < i; a++)
{
if (a > 0) txt += "\\";
txt += split[a];
}
for (; i < split.Length; i++)
{
txt = Combine(txt, split[i]);
list.Add(txt);
}
return list;
}
private static string Combine(string path1, string path2)
{
return path1.TrimEnd('\\') + "\\" + path2.TrimStart('\\').TrimEnd('.');
}
#endregion
}
NativeMethods
:
internal static class NativeMethods
{
internal const int FILE_ATTRIBUTE_ARCHIVE = 0x20;
internal const int INVALID_FILE_ATTRIBUTES = -1;
internal const int FILE_READ_DATA = 0x0001;
internal const int FILE_WRITE_DATA = 0x0002;
internal const int FILE_APPEND_DATA = 0x0004;
internal const int FILE_READ_EA = 0x0008;
internal const int FILE_WRITE_EA = 0x0010;
internal const int FILE_READ_ATTRIBUTES = 0x0080;
internal const int FILE_WRITE_ATTRIBUTES = 0x0100;
internal const int FILE_SHARE_NONE = 0x00000000;
internal const int FILE_SHARE_READ = 0x00000001;
internal const int FILE_ATTRIBUTE_DIRECTORY = 0x10;
internal const long FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
SYNCHRONIZE;
internal const long FILE_GENERIC_READ = STANDARD_RIGHTS_READ |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
SYNCHRONIZE;
internal const long READ_CONTROL = 0x00020000L;
internal const long STANDARD_RIGHTS_READ = READ_CONTROL;
internal const long STANDARD_RIGHTS_WRITE = READ_CONTROL;
internal const long SYNCHRONIZE = 0x00100000L;
internal const int CREATE_NEW = 1;
internal const int CREATE_ALWAYS = 2;
internal const int OPEN_EXISTING = 3;
internal const int MAX_PATH = 260;
internal const int MAX_ALTERNATE = 14;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct WIN32_FIND_DATA
{
public System.IO.FileAttributes dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public uint nFileSizeHigh; //changed all to uint, otherwise you run into unexpected overflow
public uint nFileSizeLow; //|
public uint dwReserved0; //|
public uint dwReserved1; //v
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ALTERNATE)]
public string cAlternate;
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool CopyFileW(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int GetFileAttributesW(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool DeleteFileW(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool MoveFileW(string lpExistingFileName, string lpNewFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool GetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool FindClose(IntPtr hFindFile);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool RemoveDirectory(string path);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool CreateDirectory(string lpPathName, IntPtr lpSecurityAttributes);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SetFileAttributesW(string lpFileName, int fileAttributes);
}
.NET Core는 이제 확장 구문없이 긴 경로 이름을 지원 합니다 .
내가 작성중인 응용 프로그램에서이 문제가 한 번 발생했습니다. 260 자 제한에 가까워 졌을 때 네트워크 드라이브를 전체 경로의 일부 세그먼트에 즉시 매핑하여 전체 경로 + 파일 이름의 길이를 크게 줄였습니다. 정말 우아한 솔루션은 아니지만 작업을 완료했습니다.
GetFileAttributesEx에 대한 MSDN 참조는 말합니다 :
이 함수의 ANSI 버전에서 이름은 MAX_PATH 문자로 제한됩니다. 이 제한을 32,767 와이드 문자로 확장하려면 함수의 유니 코드 버전을 호출하고 경로 앞에 "\\? \"를 추가하십시오. 자세한 내용 은 파일 이름 지정을 참조하십시오 .
So you want to use GetFileAttributesExW and prefix your path with "\\?\"
Please update your config file like this:
<configuration>
<runtime>
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
</runtime>
</configuration>
Creating a separate process that uses Robocopy is also a solution as discussed here: How to move folder/files with path names > 255 characters in Windows 8.1?
public static void RoboCopy(string src, string dst)
{
Process p = new Process();
p.StartInfo.Arguments = string.Format("/C Robocopy {0} {1}", src, dst);
p.StartInfo.FileName = "CMD.EXE";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
}
As seen in: File copy using robo copy and process
'code' 카테고리의 다른 글
여러 개의 try-catch 또는 하나? (0) | 2020.12.04 |
---|---|
Linux 정적 링크가 죽었습니까? (0) | 2020.12.04 |
Tomcat 7을 사용한 @WebServlet 주석 (0) | 2020.12.04 |
주어진 문자열에 주어진 하위 문자열이 포함 된 경우 관용적 스칼라 검색 방법은 무엇입니까? (0) | 2020.12.04 |
자식 MSBuild.exe 프로세스를 성공적으로 시작하거나 연결하지 못했습니다. (0) | 2020.12.04 |