PathUtils.cs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. namespace MeloongCore;
  2. public static class PathUtils {
  3. #region 分隔符
  4. /// <summary>
  5. /// 确保路径的结尾包含文件夹分隔符。
  6. /// </summary>
  7. public static string WithSeparator(string folder) => folder.EndsWithF(Path.DirectorySeparatorChar) ? folder : folder + Path.DirectorySeparatorChar;
  8. /// <summary>
  9. /// 确保路径的结尾不包含文件夹分隔符。
  10. /// </summary>
  11. public static string WithoutSeparator(string folder) => folder.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
  12. #endregion
  13. #region 长路径
  14. /// <summary>
  15. /// 若路径较长,则尽量将其转换为短路径。
  16. /// 若输入的是文件夹路径,不保证其结尾是否有文件夹分隔符。
  17. /// </summary>
  18. public static string ToShortPath(string fullName, bool keepFileName = false) {
  19. if (string.IsNullOrEmpty(fullName)) return fullName;
  20. fullName = PathUtils.WithoutLongPath( fullName.Replace('/', '\\'));
  21. if (fullName.Length <= 200) return fullName;
  22. // 保留文件名
  23. string pathToKeep = "";
  24. string pathToShorten = fullName;
  25. if (fullName.EndsWithF(".jar", true)) keepFileName = true; // jar 文件的文件名需要保留原样,否则会导致 Forge 1.20.1 无法通过文件名识别模块名
  26. if (keepFileName && FileUtils.Exists(fullName)) {
  27. pathToKeep = Path.GetFileName(fullName);
  28. pathToShorten = Path.GetDirectoryName(fullName);
  29. }
  30. // 逐级向上寻找已存在的文件夹,将不存在的部分挪到 suffix,不再缩短
  31. while (!DirectoryUtils.Exists(pathToShorten) && !FileUtils.Exists(pathToShorten)) { // 如果路径不存在
  32. string parentPath = Path.GetDirectoryName(pathToShorten);
  33. if (string.IsNullOrEmpty(parentPath) || parentPath == pathToShorten) return fullName; // 已经到达根目录,全都不存在,直接返回
  34. pathToKeep = Path.Combine(Path.GetFileName(pathToShorten), pathToKeep);
  35. pathToShorten = parentPath;
  36. }
  37. if (pathToShorten.Length <= 10) return fullName;
  38. // 缩短路径
  39. char[] buffer = new char[260];
  40. int result = GetShortPathNameW(pathToShorten, buffer, buffer.Length);
  41. if (result == 0) return fullName;
  42. string shortPath = new(buffer, 0, result);
  43. return Path.Combine(shortPath, pathToKeep);
  44. }
  45. [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
  46. private static extern int GetShortPathNameW(string lpszLongPath, [Out] char[] buffer, int cchBuffer);
  47. /// <summary>
  48. /// 将完整路径转换为以 \\?\ 开头的标准长路径格式。
  49. /// 这会去除路径末尾的分隔符,且将 / 替换为 \。
  50. /// </summary>
  51. public static string WithLongPath(string path) {
  52. if (string.IsNullOrWhiteSpace(path)) return path;
  53. if (path.StartsWithF(@"\\?\")) return path; // 已经是长路径
  54. path = WithoutSeparator(path).Replace('/', '\\'); // API 要求这个格式……
  55. return $@"\\?\{path}";
  56. }
  57. /// <summary>
  58. /// 去除路径开头的 \\?\。
  59. /// </summary>
  60. public static string WithoutLongPath(string path) =>
  61. path.AfterLast(@"\\?\");
  62. #endregion
  63. }