|
|
发表于 2026-8-20 00:35:25
|
显示全部楼层
解压这块确实比较麻烦,这会是个很好很实用的工具,但是在测试的时候发现了点小问题。起因是看到说内置的7z,我就用站内光输不赢大佬的最新资源ntr猎人进行了测试,mp4转zip确实只能用winrar,解压过程没有问题但随后出现报错处理异常:指定的路径或文件名太长,或者两者都太长。完全限定文件名必须少于 260 个字符,并且目录名必须少于 248 个字符。
对比手动解压,输出的文件缺少了一些,有意思的是缺少了这部分nwjs.app的文件没有影响游戏的启动。
我是完全不懂任何相关知识的,所有认知全部来源于ai。询问deepseek得知问题在于解压完成后,UnpackCore.MoveToFinal 方法使用 .NET 的 Directory.Move / File.Move 将整个结果目录从临时目录移动到最终输出目录(源文件所在目录)。由于最终路径(源目录 + 压缩包内部深层目录)超过 Windows 传统 MAX_PATH(260 字符)限制,且 .NET 默认未启用长路径支持,Directory.Move / File.Move 直接抛出 IOException,导致移动中断,部分文件未能到达目标位置。
给出了解决方案但是我不能验证
核心思路:给所有传给文件系统 API 的路径添加 \\?\ 长路径前缀,绕过 260 字符限制。
1. 添加路径转换辅助方法
在 UnpackCore 类中添加:
private static string ToLongPath(string path)
{
if (string.IsNullOrEmpty(path) || path.StartsWith(@"\\?\"))
return path;
return @"\\?\" + path;
}
2. 修改 MoveToFinal 方法
将原始方法替换为以下版本(注意先正常组合路径,最后统一添加前缀):
private static string MoveToFinal(string resultDir, string outputRoot, string baseName, ILog log)
{
// 先组合目标路径(不包含前缀)
string text = Path.Combine(outputRoot, baseName);
int num = 2;
while (Directory.Exists(ToLongPath(text)) || File.Exists(ToLongPath(text)))
{
text = Path.Combine(outputRoot, baseName + "_" + num);
num++;
}
Directory.CreateDirectory(ToLongPath(outputRoot)); // 确保输出根存在
if (File.Exists(ToLongPath(resultDir)))
{
Directory.CreateDirectory(ToLongPath(text));
string text2 = Path.Combine(text, Path.GetFileName(resultDir));
File.Move(ToLongPath(resultDir), ToLongPath(text2));
log.Log(" 📁 最终结果:" + text);
return text;
}
string[] fileSystemEntries = Directory.GetFileSystemEntries(ToLongPath(resultDir));
if (fileSystemEntries.Length == 1 && Directory.Exists(ToLongPath(fileSystemEntries[0])))
{
MoveDirectory(ToLongPath(fileSystemEntries[0]), ToLongPath(text));
}
else
{
MoveDirectory(ToLongPath(resultDir), ToLongPath(text));
}
log.Log(" 📁 最终结果:" + text);
return text;
}
3. 修改 MoveDirectory 和 CopyDirectory
public static void MoveDirectory(string src, string dst)
{
src = ToLongPath(src);
dst = ToLongPath(dst);
try
{
Directory.Move(src, dst);
}
catch (IOException)
{
CopyDirectory(src, dst);
Directory.Delete(src, true);
}
}
private static void CopyDirectory(string src, string dst)
{
src = ToLongPath(src);
dst = ToLongPath(dst);
Directory.CreateDirectory(dst);
foreach (string text in Directory.GetDirectories(src, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(ToLongPath(text.Replace(src, dst)));
}
foreach (string text2 in Directory.GetFiles(src, "*", SearchOption.AllDirectories))
{
File.Copy(text2, ToLongPath(text2.Replace(src, dst)), true);
}
}
4. 同时处理其他文件枚举操作(可选但推荐)
CollectTree 和 Deduplicate 中也涉及目录遍历,虽然它们被 try-catch 包裹不会导致主流程崩溃,但可能静默漏掉长路径文件。若想彻底修复,需在这些方法中同样为路径添加 \\?\ 前缀,例如:
在 CollectTree 中递归调用时,对 root、返回的目录/文件路径统一加前缀。
在 Deduplicate 中,对 Directory.GetDirectories、Directory.GetFiles 的输入路径和结果路径加前缀。
不过,当前主要问题出在 MoveToFinal,先修改这部分即可解决“解压成功但移动失败导致文件缺失”的问题。
补充建议
应用程序清单:为了让 .NET 的内置 API 原生支持长路径,可以在 exe 中嵌入 app.manifest 并包含 <longPathAware>true</longPathAware>。但即使没有,使用 \\?\ 前缀也能绕过大部分限制。
异常处理:在 ProcessGroup 的 catch 中,可以考虑保留临时目录以便用户手动恢复,目前代码已经保留了临时目录,但提示不够友好。
用户侧临时方案:在修复版发布前,用户可以启用系统长路径支持(注册表 LongPathsEnabled=1 并重启),同时将压缩包和输出目录放在短路径(如 D:\1)下,可降低触发概率。
在ds这次升级之前有试过写一些简单的代码效果非常的差,对于以上内容我持观望态度,希望有大手子能帮到你。
|
|