PathUtils.cs 3.3 KB

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