|
|
@@ -23,31 +23,31 @@ public static class PathUtils {
|
|
|
/// 若路径较长,则尽量将其转换为短路径。
|
|
|
/// <para/>结果的开头不含 <c>\\?\</c>,结尾不含分隔符。
|
|
|
/// </summary>
|
|
|
- public static string ToShortPath(string fullName, bool keepFileName = false) {
|
|
|
- if (string.IsNullOrEmpty(fullName)) return fullName;
|
|
|
- if (!fullName.Contains(@":\")) return fullName;
|
|
|
- if (fullName.Length <= 200) return fullName;
|
|
|
- fullName = PathUtils.ForCompare(fullName);
|
|
|
+ public static string ToShortPath(string pathName, bool keepFileName = false) {
|
|
|
+ if (string.IsNullOrEmpty(pathName)) return pathName;
|
|
|
+ if (!pathName.Contains(":")) return pathName;
|
|
|
+ if (pathName.Length <= 200) return pathName;
|
|
|
+ pathName = PathUtils.ForCompare(pathName);
|
|
|
// 保留文件名
|
|
|
string pathToKeep = "";
|
|
|
- string pathToShorten = fullName;
|
|
|
- if (fullName.EndsWithF(".jar", true)) keepFileName = true; // jar 文件的文件名需要保留原样,否则会导致 Forge 1.20.1 无法通过文件名识别模块名
|
|
|
- if (keepFileName && FileUtils.Exists(fullName)) {
|
|
|
- pathToKeep = PathUtils.GetLastPart(fullName);
|
|
|
- pathToShorten = PathUtils.RemoveLastPart(fullName);
|
|
|
+ string pathToShorten = pathName;
|
|
|
+ if (pathName.EndsWithF(".jar", true)) keepFileName = true; // jar 文件的文件名需要保留原样,否则会导致 Forge 1.20.1 无法通过文件名识别模块名
|
|
|
+ if (keepFileName && FileUtils.Exists(pathName)) {
|
|
|
+ pathToKeep = PathUtils.GetLastPart(pathName);
|
|
|
+ pathToShorten = PathUtils.RemoveLastPart(pathName);
|
|
|
}
|
|
|
// 逐级向上寻找已存在的文件夹,将不存在的部分挪到 suffix,不再缩短
|
|
|
while (!DirectoryUtils.Exists(pathToShorten) && !FileUtils.Exists(pathToShorten)) { // 如果路径不存在
|
|
|
string parentPath = Path.GetDirectoryName(pathToShorten);
|
|
|
- if (string.IsNullOrEmpty(parentPath) || parentPath == pathToShorten) return fullName; // 已经到达根目录,全都不存在,直接返回
|
|
|
+ if (string.IsNullOrEmpty(parentPath) || parentPath == pathToShorten) return pathName; // 已经到达根目录,全都不存在,直接返回
|
|
|
pathToKeep = Path.Combine(PathUtils.GetLastPart(pathToShorten), pathToKeep);
|
|
|
pathToShorten = parentPath;
|
|
|
}
|
|
|
- if (pathToShorten.Length <= 10) return fullName;
|
|
|
+ if (pathToShorten.Length <= 10) return pathName;
|
|
|
// 实际缩短路径
|
|
|
char[] buffer = new char[260];
|
|
|
int result = GetShortPathNameW(PathUtils.ForApi(pathToShorten), buffer, buffer.Length);
|
|
|
- if (result == 0) return fullName;
|
|
|
+ if (result == 0) return pathName;
|
|
|
string shortPath = new(buffer, 0, result);
|
|
|
return PathUtils.RemoveSlashSuffix(PathUtils.RemoveExtendedPrefix(Path.Combine(shortPath, pathToKeep)));
|
|
|
}
|
|
|
@@ -58,24 +58,25 @@ public static class PathUtils {
|
|
|
/// 将完整路径转换为以 <c>\\?\</c> 开头的扩展格式。
|
|
|
/// 这会去除路径末尾的分隔符,将 / 替换为 \。
|
|
|
/// </summary>
|
|
|
- public static string ToExtendedFormat(string path) {
|
|
|
- if (string.IsNullOrWhiteSpace(path)) return path;
|
|
|
- if (path.StartsWithF(@"\\?\")) return path; // 已经是长路径
|
|
|
- path = RemoveSlashSuffix(path).Replace('/', '\\'); // API 要求这个格式……
|
|
|
- if (path.StartsWithF(@"\\")) {
|
|
|
- return $@"\\?\UNC\{path[2..]}";
|
|
|
+ public static string ToExtendedFormat(string pathName) {
|
|
|
+ if (string.IsNullOrWhiteSpace(pathName)) return pathName;
|
|
|
+ if (!pathName.Contains(@":")) return pathName; // 可能是相对路径,保持不变
|
|
|
+ if (pathName.StartsWithF(@"\\?\")) return pathName; // 已经是长路径
|
|
|
+ pathName = RemoveSlashSuffix(pathName).Replace('/', '\\'); // API 要求这个格式……
|
|
|
+ if (pathName.StartsWithF(@"\\")) {
|
|
|
+ return $@"\\?\UNC\{pathName[2..]}";
|
|
|
} else {
|
|
|
- return $@"\\?\{path}";
|
|
|
+ return $@"\\?\{pathName}";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 去除路径开头的 <c>\\?\</c>。
|
|
|
/// </summary>
|
|
|
- public static string RemoveExtendedPrefix(string path) {
|
|
|
- if (path.StartsWithF(@"\\?\UNC\")) return @"\\" + path.AfterLast(@"\\?\UNC\");
|
|
|
- if (path.StartsWithF(@"\\?\")) return path.AfterLast(@"\\?\");
|
|
|
- return path;
|
|
|
+ public static string RemoveExtendedPrefix(string pathName) {
|
|
|
+ if (pathName.StartsWithF(@"\\?\UNC\")) return @"\\" + pathName.AfterLast(@"\\?\UNC\");
|
|
|
+ if (pathName.StartsWithF(@"\\?\")) return pathName.AfterLast(@"\\?\");
|
|
|
+ return pathName;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
@@ -91,11 +92,11 @@ public static class PathUtils {
|
|
|
/// "C:\foo\" → "C:"
|
|
|
/// "https://foo.bar/file/pack.zip?arg=1" → "https://foo.bar/file"
|
|
|
/// </code></summary>
|
|
|
- public static string RemoveLastPart(string path) {
|
|
|
- if (path!.Contains("://")) { // 网络路径
|
|
|
- path = PathUtils.RemoveSlashSuffix(path.BeforeFirst("#").BeforeFirst("?")); // 去除参数
|
|
|
+ public static string RemoveLastPart(string pathName) {
|
|
|
+ if (pathName!.Contains("://")) { // 网络路径
|
|
|
+ pathName = PathUtils.RemoveSlashSuffix(pathName.BeforeFirst("#").BeforeFirst("?")); // 去除参数
|
|
|
}
|
|
|
- return PathUtils.RemoveSlashSuffix(path!).BeforeLastOfAny([@"\", "/"]);
|
|
|
+ return PathUtils.RemoveSlashSuffix(pathName!).BeforeLastOfAny([@"\", "/"]);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -106,13 +107,13 @@ public static class PathUtils {
|
|
|
/// "C:\foo\bar" → "bar"
|
|
|
/// "https://foo.bar/file/pack.zip?arg=1" → "pack.zip"
|
|
|
/// </code></summary>
|
|
|
- public static string GetLastPart(string path) {
|
|
|
- if (path!.Contains("://")) { // 网络路径
|
|
|
- path = PathUtils.RemoveSlashSuffix(path.BeforeFirst("#").BeforeFirst("?")); // 去除参数
|
|
|
+ public static string GetLastPart(string pathName) {
|
|
|
+ if (pathName!.Contains("://")) { // 网络路径
|
|
|
+ pathName = PathUtils.RemoveSlashSuffix(pathName.BeforeFirst("#").BeforeFirst("?")); // 去除参数
|
|
|
} else { // 文件路径
|
|
|
- path = PathUtils.RemoveSlashSuffix(path);
|
|
|
+ pathName = PathUtils.RemoveSlashSuffix(pathName);
|
|
|
}
|
|
|
- return path.AfterLastOfAny([@"\", "/"]);
|
|
|
+ return pathName.AfterLastOfAny([@"\", "/"]);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -123,8 +124,8 @@ public static class PathUtils {
|
|
|
/// "https://foo.bar/file/page.xaml.vb?arg=1" → "page.xaml"
|
|
|
/// </code>
|
|
|
/// </summary>
|
|
|
- public static string GetFileNameWithoutExtension(string path)
|
|
|
- => GetLastPart(path).BeforeLast(".");
|
|
|
+ public static string GetFileNameWithoutExtension(string pathName)
|
|
|
+ => GetLastPart(pathName).BeforeLast(".");
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取路径或文件名中的最后一级文件扩展名,不包含 <c>.</c>,固定小写。
|
|
|
@@ -136,8 +137,8 @@ public static class PathUtils {
|
|
|
/// "https://foo.bar/file/page.xaml.vb?arg=1" → "vb"
|
|
|
/// </code>
|
|
|
/// </summary>
|
|
|
- public static string GetExtension(string path) {
|
|
|
- var name = GetLastPart(path);
|
|
|
+ public static string GetExtension(string pathName) {
|
|
|
+ var name = GetLastPart(pathName);
|
|
|
return name.Contains(".") ? name.AfterLast(".").Lower() : "";
|
|
|
}
|
|
|
|
|
|
@@ -145,29 +146,29 @@ public static class PathUtils {
|
|
|
/// 获取路径的盘符,返回一个大写字母。
|
|
|
/// 若路径不包含盘符,则返回 <c>null</c>。
|
|
|
/// </summary>
|
|
|
- public static char? GetDiskName(string? path) {
|
|
|
- if (string.IsNullOrEmpty(path)) return null;
|
|
|
- path = PathUtils.RemoveExtendedPrefix(path!);
|
|
|
- if (path.StartsWithF(@"\\") || path.StartsWithF("/")) return null;
|
|
|
- return char.ToUpper(path[0]);
|
|
|
+ public static char? GetDiskName(string? pathName) {
|
|
|
+ if (string.IsNullOrEmpty(pathName)) return null;
|
|
|
+ pathName = PathUtils.RemoveExtendedPrefix(pathName!);
|
|
|
+ if (pathName.StartsWithF(@"\\") || pathName.StartsWithF("/")) return null;
|
|
|
+ return char.ToUpper(pathName[0]);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 统一路径格式,以便比较。
|
|
|
/// <para/>具体而言:将短路径展开,去除前导的 <c>\\?\</c>,将分隔符改为 \,去除末尾的分隔符。
|
|
|
/// </summary>
|
|
|
- public static string ForCompare(string path)
|
|
|
- => PathUtils.RemoveSlashSuffix(PathUtils.RemoveExtendedPrefix(Path.GetFullPath(path)).Replace("/", @"\"));
|
|
|
+ public static string ForCompare(string pathName)
|
|
|
+ => PathUtils.RemoveSlashSuffix(PathUtils.RemoveExtendedPrefix(Path.GetFullPath(pathName)).Replace("/", @"\"));
|
|
|
|
|
|
/// <summary>
|
|
|
/// 将路径转换为兼容各种 Windows API 的格式。
|
|
|
/// <para/>具体而言:将分隔符改为 \。添加前导的 <c>\\?\</c>。若为驱动器则添加末尾分隔符,否则去除分隔符。
|
|
|
/// </summary>
|
|
|
- public static string ForApi(string path) {
|
|
|
- path = PathUtils.ToExtendedFormat(path);
|
|
|
- if (path.EndsWithF(":")) path += @"\"; // 驱动器路径必须保留末尾的分隔符
|
|
|
- if (path.EndsWithF(@":\")) return path;
|
|
|
- return PathUtils.RemoveSlashSuffix(path);
|
|
|
+ public static string ForApi(string pathName) {
|
|
|
+ pathName = PathUtils.ToExtendedFormat(pathName);
|
|
|
+ if (pathName.EndsWithF(":")) pathName += @"\"; // 驱动器路径必须保留末尾的分隔符
|
|
|
+ if (pathName.EndsWithF(@":\")) return pathName;
|
|
|
+ return PathUtils.RemoveSlashSuffix(pathName);
|
|
|
}
|
|
|
|
|
|
#endregion
|