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 個字符的最長路徑

 

參考

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