Unity Windows 路径长度限制踩坑

错误日志

今天在 Windows 上打 PC 包时遇到了这样的报错:

Console 输出的详细错误日志:

IOException: Failed to Move File / Directory from 'Temp/StagingArea\bunny rummy_Data\StreamingAssets\lua\logic\ui\pnl_activity\first_add_cash\first_add_cash_activity_preselected_item\ui_first_add_cash_activity_preselected_item_logic.lua' to 'C:\TS\rummy_itc\Assets\..\z_package\debug\bunny_rummy_8-3-3-4_v1.0.1.20_20200427_153115\bunny rummy_Data\StreamingAssets\lua\logic\ui\pnl_activity\first_add_cash\first_add_cash_activity_preselected_item\ui_first_add_cash_activity_preselected_item_logic.lua'.
UnityEditor.FileUtil.MoveFileOrDirectory (System.String source, System.String dest) (at C:/buildslave/unity/build/Editor/Mono/FileUtil.bindings.cs:77)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:428)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyFilesToDestination (System.String source, System.String target, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:432)
DesktopStandalonePostProcessor.CopyStagingAreaIntoDestination (UnityEditor.Modules.BuildPostProcessArgs args, System.Collections.Generic.HashSet`1[T] filesToNotOverwrite) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:402)
DesktopStandalonePostProcessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args) (at C:/buildslave/unity/build/Editor/Mono/BuildPipeline/DesktopStandalonePostProcessor.cs:51)
UnityEditor.BuildPipeline:BuildPlayer(String[], String, BuildTarget, BuildOptions)
PackAppPatch:GenPackage() (at Assets/Code/Editor/Package/PackAppPatch.cs:342)
PackAppPatch:DoPackApp(CPackArg) (at Assets/Code/Editor/Package/PackAppPatch.cs:203)
PackGUI:OnClickPackage() (at Assets/Code/Editor/Package/PackGUI.cs:54)
PackGUI:BranchConfirm(Action) (at Assets/Code/Editor/Package/PackGUI.cs:311)
<>c__DisplayClass9_0:<OnGUI>b__1() (at Assets/Code/Editor/Package/PackGUI.cs:112)
GuiUtil:RegSceneBtn(String, String, Action) (at Assets/Code/Editor/GuiUtil.cs:30)
PackGUI:OnGUI() (at Assets/Code/Editor/Package/PackGUI.cs:110)
PackGUI:Draw() (at Assets/Code/Editor/Package/PackGUI.cs:23)
UtilTemplate`2:OnGUI() (at Assets/Code/Editor/UtilBase/UtilTemplate.cs:55)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

看起来貌似是拷贝文件时拷贝失败了,核心的报错内容是这部分:

IOException: Failed to Move File / Directory from 'Temp/StagingArea\bunny rummy_Data\StreamingAssets\lua\logic\ui\pnl_activity\first_add_cash\first_add_cash_activity_preselected_item\ui_first_add_cash_activity_preselected_item_logic.lua' to 'C:\TS\rummy_itc\Assets\..\z_package\debug\bunny_rummy_8-3-3-4_v1.0.1.20_20200427_153115\bunny rummy_Data\StreamingAssets\lua\logic\ui\pnl_activity\first_add_cash\first_add_cash_activity_preselected_item\ui_first_add_cash_activity_preselected_item_logic.lua'.
UnityEditor.FileUtil.MoveFileOrDirectory (System.String source, System.String dest) (at C:/buildslave/unity/build/Editor/Mono/FileUtil.bindings.cs:77)

即调用 UnityEditor.FileUtil.MoveFileOrDirectory API 去复制文件的时候出错了

 

错误分析

其实之前出现过,使用相同内容的工程打包,在 C 盘下的工程可以打包,在 E 盘下不能打包,区别就是路径不同,如下:

  • C 盘工程路径:C:\TS\rummy_itc

  • D 盘工程路径:E:\U3DProjects\rummy_itc_copy

显然路径长度不同,只是 C 盘可以打包成功了就暂时没去理会。

这次 C 盘的工程也出现打包问题了,而且可以看到报错的路径长度很长,特别是复制目标文件的路径 'C:\TS\rummy_itc\Assets\..\z_package\debug\bunny_rummy_8-3-3-4_v1.0.1.20_20200427_153115\bunny rummy_Data\StreamingAssets\lua\logic\ui\pnl_activity\first_add_cash\first_add_cash_activity_preselected_item\ui_first_add_cash_activity_preselected_item_logic.lua' ,使用在线计算工具统计的结果:

字符长度为 256,初步猜测是路径超过 Windows 路径的长度限制。

 

Windows 限制

在 Windows API 中,通过 MAX_PATH 来限制路径得最大长度,MAX_PATH 被定义为 260

一般路径得结构:

|盘符|冒号|反斜杠|被分斜杠分割的具体路径|NUL('\0')|

例如:D:\<dir>NUL

最后的 NUL 是终止符,也可以用 '\0' 表示 ,因此,去除盘符的目录的相对路径 dir 长度不能超过 256,这里对于目录和文件的限制有所区别:

  • 目录:248

  • 文件:256

Windows API 中会将 '/' 转为 '\'

 

测试

将上面报错的目标路径修改进行测试,测试代码如下:

String src = "Temp/StagingArea/bunny rummy_Data/StreamingAssets/lua/logic/ui/pnl_activity/first_add_cash/first_add_cash_activity_preselected_item/ui_first_add_cash_activity_preselected_item_logic.lua";
String des = "C:/TS/rummy_itc/Assets/../z_package/debug/bunny_rummy_8-3-3-4_v1.0.1.20_20200427_105542/bunny rummy_Data/StreamingAssets/lua/logic/ui/pnl_activity/first_add_cash/first_add_cash_activity_preselected_item/ui_first_add_cash_activity_preselected_item_logic.lua";
FileUtil.CopyFileOrDirectory(src, des);

测试结果是将文件名删除一部分,改为 ui_first_add_cash_activity_preselected_item_ ,最终总路径长度为 247 才能复制成功。

 

总结

像这样的问题只能在开发时,通过一些规范来规避,主要需要注意几点:

  • Unity 工程位置不要放得太深,尽量放在磁盘根路径下或二级路径,如 :D:\U3DProjs

  • 工程内文件名不要太长,像 ui_first_add_cash_activity_preselected_item_logic.lua 这样的取名方式有点逆天了,尽量用缩写

  • 工程内目录不要创建太多级,且目录名不要太长

 

其他

MSDN 提到,可以通过 "\\?\" 前缀加上至多 255 长度的字符串来表示长达 32000 个字符的最长路径

 

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章