https://docs.microsoft.com/zh-cn/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN
https://docs.microsoft.com/zh-cn/windows/win32/fileio/maximum-file-path-limitation
Windows支持的所有文件系統都使用文件和目錄的概念來訪問存儲在磁盤或設備上的數據。使用Windows API進行文件和設備I / O的Windows開發人員應了解文件和目錄名稱的各種規則,約定和限制。
可以使用文件I / O API從磁盤,設備和網絡共享訪問數據。文件和目錄以及名稱空間是路徑概念的一部分,路徑是對數據獲取位置的字符串表示,無論數據是來自磁盤,設備還是用於特定操作的網絡連接。
某些文件系統(例如NTFS)支持鏈接的文件和目錄,它們也遵循文件命名約定和規則,就像常規文件或目錄一樣。有關更多信息,請參見“硬鏈接和連接點以及重新解析點和文件操作”。
有關其他信息,請參見以下小節:
文件名和目錄名
命名約定
短名與長名
路徑
完全合格與相對路徑
最大路徑長度限制
命名空間
Win32文件命名空間
Win32設備命名空間
NT命名空間
相關話題
要了解有關配置Windows 10以支持長文件路徑的信息,請參閱最大路徑長度限制。
文件名和目錄名
對於單個文件,所有文件系統都遵循相同的通用命名約定:基本文件名和可選的擴展名,以句點分隔。但是,每個文件系統(例如NTFS,CDFS,exFAT,UDFS,FAT和FAT32)對於在目錄或文件路徑中各個組件的形成都可以有特定且不同的規則。請注意,目錄只是具有特殊屬性的文件,將其指定為目錄,但否則必須遵循與常規文件相同的所有命名規則。因為就文件系統而言,目錄一詞僅指一種特殊類型的文件,所以某些參考資料將使用通用術語“文件”。包含目錄和數據文件本身的概念。因此,除非另有說明,否則文件的任何命名或使用規則或示例也應適用於目錄。術語路徑是指一個或多個目錄,反斜杠以及可能的卷名。有關更多信息,請參見路徑部分。
字符數限制也可以不同,並且可以根據文件系統和使用的路徑名前綴格式而有所不同。對后向兼容機制的支持使情況更加復雜。例如,較舊的MS-DOS FAT文件系統最多支持8個字符的基本文件名和3個擴展名的字符,包括點分隔符在內總共12個字符。這通常稱為8.3文件名。Windows FAT和NTFS文件系統不限於8.3文件名,因為它們支持長文件名,但它們仍支持8.3版本的長文件名。
命名約定
以下基本規則使應用程序可以創建和處理文件和目錄的有效名稱,而與文件系統無關:
使用句點將基本文件名與目錄或文件名中的擴展名分開。
使用反斜杠(\)到分離的部件a的路徑。反斜杠將文件名從路徑分開,並將一個目錄名與路徑中的另一個目錄名分開。您不能在實際文件或目錄的名稱中使用反斜杠,因為它是一個保留字符,將名稱分隔為多個部分。
作為卷名的一部分,請根據需要使用反斜杠,例如,“ C:\ path \ file”中的“ C:\”或“ \\ server \ share \ path \ file”中的“ \\ server \ share”通用命名約定(UNC)名稱。有關UNC名稱的更多信息,請參見最大路徑長度限制部分。
不要假設大小寫敏感。例如,即使某些文件系統(例如POSIX兼容文件系統)可能認為它們不同,也應將名稱OSCAR,Oscar和oscar視為相同。請注意,NTFS支持POSIX語義以區分大小寫,但這不是默認行為。有關更多信息,請參見CreateFile。
卷號(驅動器號)類似地不區分大小寫。例如,“ D:\”和“ d:\”指的是同一卷。
使用當前代碼頁中的任何字符作為名稱,包括Unicode字符和擴展字符集(128–255)中的字符,但以下各項除外:
以下保留字符:
<(小於)
>(大於)
:(冒號)
”(雙引號)
/(正斜杠)
\(反斜杠)
| (垂直桿或管)
?(問號)
*(星號)
整數值零,有時也稱為ASCII NUL字符。
整數表示形式在1到31之間的字符,但允許這些字符的備用數據流除外。有關文件流的更多信息,請參見文件流。
目標文件系統不允許的任何其他字符。
使用句點作為路徑中代表當前目錄的目錄組件,例如“。\ temp.txt”。有關更多信息,請參見路徑。
使用兩個連續的句點(..)作為路徑中的目錄組成部分,以表示當前目錄的父目錄,例如“ .. \ temp.txt”。有關更多信息,請參見路徑。
不要將以下保留名稱用作文件名:
CON,PRN,AUX,NUL,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8和LPT9。也要避免在這些名稱后面加上擴展名;例如,不建議使用NUL.txt。有關更多信息,請參見命名空間。
文件名或目錄名不要以空格或句號結尾。盡管基礎文件系統可能支持此類名稱,但Windows Shell和用戶界面不支持。但是,可以將句點指定為名稱的第一個字符。例如,“。temp”。
短名與長名
長文件名被認為是任何超出短MS-DOS(也稱為8.3)樣式命名約定的文件名。當您創建一個長文件名時,Windows可能還會創建一個簡短的8.3形式的名稱(稱為8.3別名或簡稱),並將其也存儲在磁盤上。出於性能原因,可以在系統范圍內或為指定的卷禁用此8.3別名,具體取決於特定的文件系統。
Windows Server 2008,Windows Vista,Windows Server 2003和Windows XP:在Windows 7和Windows Server 2008 R2之前,不能為指定的卷禁用8.3別名。
在許多文件系統上,文件名的每個組成部分中都將包含波浪號(〜),該波浪號太長而無法遵守8.3命名規則。
備注
並非所有文件系統都遵循波浪號替換約定,並且可以將系統配置為禁用8.3別名生成,即使它們通常支持它也是如此。因此,請勿假設磁盤上已經存在8.3別名。
要從系統請求8.3文件名,長文件名或文件的完整路徑,請考慮以下選項:
要獲取8.3格式的長文件名,請使用GetShortPathName函數。
要獲取短名稱的長文件名版本,請使用GetLongPathName函數。
要獲取文件的完整路徑,請使用GetFullPathName函數。
在較新的文件系統(例如NTFS,exFAT,UDFS和FAT32)上,Windows使用Unicode將長文件名存儲在磁盤上,這意味着始終保留原始長文件名。即使長文件名包含擴展字符也是如此,無論在磁盤讀取或寫入操作期間處於活動狀態的代碼頁如何。
可以在NTFS文件系統分區和Windows FAT文件系統分區之間復制使用長文件名的文件,而不會丟失任何文件名信息。對於較早的MS-DOS FAT和某些類型的CDFS(CD-ROM)文件系統,這可能不是正確的,具體取決於實際的文件名。在這種情況下,如果可能,將替換短文件名。
路徑
指定文件的路徑由一個或多個組件組成,並用特殊字符(反斜杠)分隔,每個組件通常是目錄名或文件名,但下面將討論一些值得注意的例外。對於系統對路徑的解釋,通常至關重要的是該路徑的開始或前綴是什么樣的。該前綴確定路徑正在使用的名稱空間,另外還確定在路徑中哪個位置使用哪些特殊字符,包括最后一個字符。
如果路徑的組成部分是文件名,則它必須是最后一個組成部分。
路徑的每個組成部分還將受到為特定文件系統指定的最大長度的約束。通常,這些規則分為兩類:short和long。請注意,目錄名由文件系統存儲為特殊類型的文件,但是文件的命名規則也適用於目錄名。總而言之,路徑只是針對特定文件或目錄名稱存在的所有目錄之間的層次結構的字符串表示形式。
完全合格與相對路徑
對於操作文件的Windows API函數,文件名通常可以相對於當前目錄,而某些API需要完全限定的路徑。如果文件名不是以下列之一開頭,則它是相對於當前目錄的:
任意格式的UNC名稱,始終以兩個反斜杠字符(“ \\”)開頭。有關更多信息,請參見下一節。
帶有反斜杠的磁盤標識符,例如“ C:\”或“ d:\”。
單個反斜杠,例如“ \ directory”或“ \ file.txt”。這也稱為絕對路徑。
如果文件名僅以磁盤標識符開頭,而不以冒號后的反斜杠開頭,則將其解釋為驅動器上具有指定字母的當前目錄的相對路徑。請注意,當前目錄可能是根目錄,也可能不是根目錄,這取決於在該磁盤上進行最新“更改目錄”操作期間設置的根目錄。此格式的示例如下:
“ C:tmp.txt”是指驅動器C上當前目錄中名為“ tmp.txt”的文件。
“ C:tempdir \ tmp.txt”是指驅動器C上當前目錄的子目錄中的文件。
如果路徑包含“雙點”,則也稱為相對路徑。也就是說,在路徑的一個分量中兩個周期在一起。該特殊說明符用於表示當前目錄上方的目錄,否則稱為“父目錄”。此格式的示例如下:
“ .. \ tmp.txt”指定位於當前目錄的父目錄中的名為tmp.txt的文件。
“ .. \ .. \ tmp.txt”指定一個文件,該文件位於當前目錄的上方兩個目錄中。
“ .. \ tempdir \ tmp.txt”指定位於名為tempdir的目錄中的名為tmp.txt的文件,該目錄是當前目錄的對等目錄。
相對路徑可以合並兩個示例類型,例如“ C:.. \ tmp.txt”。這很有用,因為盡管系統會跟蹤當前驅動器以及該驅動器的當前目錄,但它也會跟蹤每個不同驅動器號(如果您的系統有多個)中的當前目錄,無論哪個驅動器指示符被設置為當前驅動器。
最大路徑長度限制
在Windows 10版本1607之前的Windows版本中,路徑的最大長度是MAX_PATH,它定義為260個字符。在Windows的更高版本中,需要更改注冊表項或使用組策略工具才能刪除限制。有關完整詳細信息,請參見最大路徑長度限制。
命名空間
Windows API中使用的命名空間約定主要有兩類,通常稱為NT命名空間和Win32命名空間。NT名稱空間被設計為可能存在其他子系統和名稱空間的最低級別名稱空間,包括Win32子系統,以及擴展的Win32名稱空間。POSIX是Windows中基於NT名稱空間構建的子系統的另一個示例。Windows的早期版本還為某些特殊設備(如通信(串行和並行)端口和默認顯示控制台)定義了一些預定義或保留的名稱,這些名稱現在稱為NT設備名稱空間,在當前版本中仍受支持。 Windows的向后兼容性。
Win32文件命名空間
本節和下一節總結了Win32名稱空間前綴和約定,並說明了如何使用它們。請注意,這些示例旨在與Windows API函數一起使用,並不一定都與Windows Shell應用程序(例如Windows Explorer)一起使用。因此,與Windows Shell應用程序相比,可能的路徑范圍更廣,可以使用這些命名空間約定來開發利用此功能的Windows應用程序。
對於文件I / O,路徑字符串的前綴“ \\?\”告訴Windows API禁用所有字符串解析,並將其后的字符串直接發送到文件系統。例如,如果文件系統支持大路徑和文件名,則可以超過Windows API強制實施的MAX_PATH限制。有關正常最大路徑限制的更多信息,請參見上一節“最大路徑長度限制”。
因為它關閉了路徑字符串的自動擴展,所以“ \\?\”前綴也允許使用“ ..”和“。”。在路徑名中,如果您嘗試使用這些保留的相對路徑說明符作為標准路徑的一部分來對文件執行操作,這將很有用。
許多但不是全部文件I / O API支持“ \\?\”;您應該查看每個API的參考主題以確保。
請注意,應使用Unicode API來確保前綴“ \\?\”允許您超出MAX_PATH
Win32設備命名空間
“ \\。\”前綴將訪問Win32設備名稱空間,而不是Win32文件名稱空間。如果API支持這種訪問方式,則可以直接完成對物理磁盤和卷的訪問,而無需通過文件系統。您可以通過這種方式訪問磁盤以外的許多設備(例如,使用CreateFile和DefineDosDevice函數)。
例如,如果要打開系統的串行通信端口1,則可以在對CreateFile函數的調用中使用“ COM1” 。這是可行的,因為COM1-COM9是NT名稱空間中保留名稱的一部分,盡管使用“ \\。\”前綴也可以與這些設備名稱一起使用。相比之下,如果您安裝了100端口串行擴展板並想打開COM56,則不能使用“ COM56”打開它,因為沒有針對COM56的預定義NT名稱空間。您將需要使用“ \\。\ COM56”打開它,因為“ \\。\”直接轉到設備名稱空間,而不會嘗試找到預定義的別名。
使用Win32設備名稱空間的另一個示例是將CreateFile函數與“ \\。\ PhysicalDisk X ”(其中X是有效的整數值)或“ \\。\ CdRom X ”一起使用。這樣,您可以繞過文件系統直接訪問那些設備。之所以可行,是因為這些設備名稱是由系統在枚舉這些設備時創建的,並且某些驅動程序還將在系統中創建其他別名。例如,實現名稱“ C:\”的設備驅動程序具有自己的名稱空間,該名稱空間也恰好是文件系統。
通過CreateFile函數的API通常使用“ \\。\”前綴,因為CreateFile是用於打開文件和設備的函數,具體取決於您使用的參數。
如果使用Windows API函數,則應使用“ \\。\”前綴僅訪問設備,而不訪問文件。
大多數API不支持“ \\。\”;只有那些旨在與設備名稱空間一起使用的設備才能識別它。請務必檢查每個API的參考主題,以確保正確。
NT命名空間
還有一些API允許使用NT名稱空間約定,但是Windows Object Manager在大多數情況下都不需要這樣做。為了說明這一點,使用Windows Sysinternals WinObj在系統對象瀏覽器中瀏覽Windows命名空間非常有用。工具。運行此工具時,您看到的是從根(或“ \”)開始的NT名稱空間。子文件夾稱為“ Global ??” 是Win32名稱空間所在的位置。命名的設備對象位於“設備”子目錄中的NT名稱空間中。在這里,您還可以找到Serial0和Serial1,它們是表示系統上存在的前兩個COM端口的設備對象。代表卷的設備對象將類似於“ HarddiskVolume1”,盡管數字后綴可能有所不同。子目錄“ Harddisk0”下的名稱“ DR0”是代表磁盤的設備對象的示例,依此類推。
為了使Windows設備可以訪問這些設備對象,設備驅動程序在Win32命名空間“ Global ??”中創建指向其各自設備對象的符號鏈接(symlink)。例如,“ Global ??”下的COM0和COM1 子目錄只是指向Serial0和Serial1的符號鏈接,“ C:”是指向HarddiskVolume1的符號鏈接,“ Physicaldrive0”是指向DR0的符號鏈接,依此類推。如果沒有符號鏈接,則如上所述,使用Win32名稱空間約定的Windows應用程序將無法使用指定的設備“ Xxx”。但是,可以使用任何支持“ \ Device \ Xxx”格式的NT命名空間絕對路徑的API對該設備打開句柄。
通過終端服務和虛擬機增加了多用戶支持,進一步有必要在Win32名稱空間內虛擬化系統范圍的根設備。這是通過在Win32名稱空間中添加名為“ GLOBALROOT”的符號鏈接來完成的,您可以在“ Global ??”中看到該符號鏈接。先前討論的WinObj瀏覽器工具的子目錄,並且可以通過路徑“ \\?\ GLOBALROOT”進行訪問。此前綴確保其后的路徑顯示在系統對象管理器的真實根路徑中,而不是會話相關的路徑中。
最大路徑長度限制
在Windows API(以下段落討論了一些例外)中,路徑的最大長度為MAX_PATH,它定義為260個字符。本地路徑按以下順序構造:驅動器號,冒號,反斜杠,用反斜杠分隔的名稱組件以及終止的空字符。例如,驅動器D上的最大路徑是“ D:\ 256個字符的字符串<NUL>”,其中“ <NUL>”代表當前系統代碼頁的不可見終止空字符。(此處使用字符<>是為了清晰起見,並且不能成為有效路徑字符串的一部分。)
例如,如果將具有長文件名的git repo克隆到本身具有長名的文件夾中,則可能會遇到此限制。
備注
Windows API中的文件I / O函數在將名稱轉換為NT樣式名稱的過程中將“ /”轉換為“ \”,除非使用“ \\?\”前綴(如以下各節所述)。
Windows API具有許多功能,這些功能還具有Unicode版本,以允許使用擴展長度的路徑,最大總路徑長度為32,767個字符。這種類型的路徑由用反斜杠分隔的組件組成,每個反斜杠都取決於GetVolumeInformation函數的lpMaximumComponentLength參數中返回的值(該值通常為255個字符)。要指定擴展長度的路徑,請使用“ \\?\”前綴。例如,“ \\?\ D:\非常長的路徑”。
備注
最大路徑為32,767個字符,這是近似值,因為系統可能會在運行時將“ \\?\”前綴擴展為更長的字符串,並且這種擴展適用於總長度。
“ \\?\”前綴也可以與根據通用命名約定(UNC)構造的路徑一起使用。要使用UNC指定這樣的路徑,請使用“ \\?\ UNC \”前綴。例如,“ \\?\ UNC \ server \ share”,其中“ server”是計算機的名稱,“ share”是共享文件夾的名稱。這些前綴不用作路徑本身的一部分。它們指示路徑應該以最小的修改傳遞給系統,這意味着您不能使用斜杠來表示路徑分隔符,也不能使用句號來表示當前目錄,也不能使用雙點號來表示父目錄。因為您不能在相對路徑中使用“ \\?\”前綴,所以相對路徑始終限制為總共MAX_PATH個字符。
無需對Windows文件I / O API函數使用的路徑和文件名字符串執行任何Unicode規范化,因為文件系統將路徑和文件名視為WCHAR的不透明序列。請記住,在對相關Windows文件I / O API函數的任何調用之外,應執行應用程序所需的任何規范化。
使用API創建目錄時,指定的路徑不能太長,以至於不能追加8.3文件名(即,目錄名不能超過MAX_PATH減12)。
外殼和文件系統有不同的要求。可以使用Windows API創建Shell用戶界面無法正確解釋的路徑。
在Windows 10版本1607和更高版本中啟用長路徑
從Windows 10版本1607開始,MAX_PATH限制已從常見的Win32文件和目錄功能中刪除。但是,您必須選擇加入新行為。
要啟用新的長路徑行為,必須滿足以下兩個條件:
注冊表項Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled (Type: REG_DWORD)必須存在並設置為1。在首次調用受影響的Win32文件或目錄函數(請參閱下面的函數列表)后,注冊表值將由系統(每個進程)緩存。在該過程的生存期內,將不會重新加載注冊表項。為了使系統上的所有應用都能識別密鑰的值,可能需要重新啟動,因為在設置密鑰之前可能已經啟動了某些進程。
備注
也可以通過位於的組策略來控制此注冊表項Computer Configuration > Administrative Templates > System > Filesystem > Enable Win32 long paths。
該應用程序清單還必須包括longPathAware的元素。
XML格式
復制中
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
如果您選擇采用長路徑行為,這些目錄管理功能將不再具有MAX_PATH限制:CreateDirectoryW,CreateDirectoryExW GetCurrentDirectoryW RemoveDirectoryW SetCurrentDirectoryW。
如果您選擇采用長路徑行為,這些文件管理功能將不再具有MAX_PATH限制:CopyFileW,CopyFile2,CopyFileExW,CreateFileW,CreateFile2,CreateHardLinkW,CreateSymbolicLinkW,DeleteFileW,FindFirstFileW,FindFirstFileExW,FindNextFileW,GetFileAttributesW,GetFileAttributesExW,SetFileAttributesW GetFullPathNameW,GetLongPathNameW,MoveFileW,MoveFileExW,MoveFileWithProgressW,ReplaceFileW,SearchPathW,FindFirstFileNameW,FindNextFileNameW,FindFirstStreamW,FindNextStreamW,GetCompressedFileSizeW,GetFinalPathNameByHandleW。
無法刪除 NTFS 文件系統卷上的文件或文件夾
內部,NTFS 將文件夾視為一種特殊類型的文件。 因此,本文中的 word 文件 表示文件或文件夾。
原因1:文件使用 ACL
如果文件使用 (ACL) 的訪問控制列表,則可能無法刪除該文件。 若要解決此問題,請更改文件的權限。 您可能需要取得文件的所有權才能更改權限。
管理員具有獲得任何文件所有權的隱式能力,即使尚未明確向其授予對該文件的任何權限也是如此。 文件所有者具有修改文件權限的隱式能力,即使沒有明確向用戶授予對文件的任何權限也是如此。 因此,您可能必須取得文件的所有權,授予自己刪除文件的權限,然后再刪除該文件。
您不能使用某些安全工具來顯示或修改權限,因為文件具有不規范的 ACL
若要解決此問題,請使用另一個工具 (例如,Cacls.exe) 的更高版本。
ACL 中 (Ace) 的訪問控制項具有特定的首選順序,具體取決於它們的類型。 例如,拒絕訪問的 Ace 通常位於授予訪問權限的 Ace 之前。 但是,任何操作都不會阻止程序以任意順序寫入具有 Ace 的 ACL。 在某些早期版本的 Windows 中,Microsoft Windows 嘗試讀取這些不規范的 Acl 時出現問題。 有時,不能使用 Microsoft Windows 資源管理器圖形安全編輯器正確修改這些 Acl。 此問題已在 Windows 的更高版本中得到更正。 如果遇到此問題,請使用 Cacls.exe 的最新版本。 即使無法就地顯示或編輯 ACL,也可以編寫一個新的 ACL,讓您獲取對文件的訪問權限。
原因2:文件正在使用
如果文件正在使用,您可能無法刪除該文件。 若要解決此問題,請確定具有打開句柄的進程,然后關閉該進程。
根據文件的打開方式 (例如,以獨占訪問方式打開(而不是共享訪問) )時,您可能無法刪除正在使用的文件。 您可以使用多種工具來幫助您根據需要隨時確定具有打開的文件句柄的進程。
此問題的症狀可能有所不同。 您可以使用 Delete 命令刪除文件,但在打開文件的進程釋放文件之前,不會刪除該文件。 此外,您可能無法訪問掛起刪除的文件的安全性對話框。 若要解決此問題,請確定具有打開句柄的進程,然后關閉該進程。
原因3:文件系統損壞阻止對文件的訪問
如果文件系統已損壞,則可能無法刪除該文件。 若要解決此問題,請在磁盤卷上運行 Chkdsk 實用工具以更正任何錯誤。
磁盤上的壞扇區、其他有故障的硬件或軟件錯誤可能會損壞文件系統並使文件處於有問題的狀態。 典型操作可能會以多種方式失敗。 當文件系統檢測到損壞時,它會將事件記錄到事件日志,並且您通常會收到一條消息,提示您運行 Chkdsk。 根據損壞的性質,Chkdsk 可能無法恢復文件數據,也可能無法恢復。但是,Chkdsk 會將文件系統返回到內部一致的狀態。
原因4:文件存在於 MAX_PATH 個字符更深層的路徑中
如果文件路徑有問題,您可能無法打開、編輯或刪除文件。
解決方法1:使用自動生成的8.3 名稱訪問文件
若要解決此問題,您可能需要使用自動生成的8.3 名稱來訪問該文件。 如果路徑深度太長,則此解決方案可能是最簡單的解決方案,因為文件夾名稱太長。 如果8.3 路徑也太長,或者如果在卷上禁用了8.3 名稱,請轉到 " 解決方法 2"。 有關在 NTFS 卷上禁用8.3 文件名稱的詳細信息,請參閱 如何禁用 ntfs 分區上的8.3 名稱創建。
解決方案2:重命名或移動深層文件夾
重命名文件夾,使目標文件的深度大於不再存在的目標文件 MAX_PATH
。 如果這樣做,請從根文件夾 (或任何其他方便的位置) ,然后重命名文件夾,以便它們的名稱較短。 如果此步驟不能解決此問題 (例如,如果文件的文件夾深度) 超過128,請轉到 " 解決方法 4"。
解決方案3:將驅動器映射到路徑結構中的文件夾
將驅動器映射到目標文件或文件夾的路徑結構中的文件夾。 此方法縮短了虛擬路徑。
例如,假設您有一個路徑,其結構如下所示:
\\ServerName\SubfolderName1\SubfolderName2\SubfolderName3\SubfolderName4\...
在此路徑中,總字符數超過255個字符。 若要將此路徑的長度縮短到73個字符,請將驅動器映射到 SubfolderName4。
解決方案4:使用作為文件夾的深度的網絡共享
如果解決辦法1、2和3不太方便或不能解決問題,請創建一個在文件夾樹中的深度更深的網絡共享,然后通過訪問共享來重命名這些文件夾。
解決方案5:使用可遍歷深度路徑的工具
許多 Windows 程序預計最大路徑長度應少於255個字符。 因此,這些程序只分配足夠的內部存儲來處理這些典型的路徑。 NTFS 不具有此限制,可以保留更長的路徑。
如果您在文件夾結構中已有相當深的某個點創建共享,然后使用該共享在該點下面創建一個深層結構,則可能會遇到此問題。 在文件夾樹本地運行的某些工具可能無法遍歷從根開始的整個樹。 您可能需要以特殊方式使用這些工具,以便它們可以遍歷共享。 (CreateFile API 文檔介紹了在這種情況下遍歷整個樹的方法。 )
通常情況下,可以使用創建文件的軟件來管理文件。 如果您有一個可以創建更早文件的程序 MAX_PATH
,則通常可以使用相同的程序來刪除或管理這些文件。 您通常可以使用相同的共享刪除在共享上創建的文件。
原因5:文件名包含 Win32 名稱空間中的保留名稱
如果文件名包含保留名稱 (例如,lpt1) 在 Win32 名稱空間中,則可能無法刪除該文件。 若要解決此問題,請使用非 Win32 程序重命名該文件。 您可以使用 POSIX 工具或使用適當的內部語法的任何其他工具來使用該文件。
此外,如果您使用特定語法來指定文件的路徑,則可以使用某些內置命令繞過典型的 Win32 保留名稱檢查。
如果使用典型的 Win32 CreateFile 機制打開文件句柄,則會為舊樣式的 DOS 設備保留某些文件名。 為了實現向后兼容,不允許使用這些文件名,也不能使用典型的 Win32 文件調用來創建這些文件名。 但是,此問題並不是 NTFS 的限制。
您可以使用 Win32 程序繞過在創建文件 (或) 刪除文件時執行的典型名稱檢查,方法是使用用於遍歷更早的文件夾的相同技術 MAX_PATH
。 此外,某些 POSIX 工具不受這些名稱檢查的制約。
原因6:文件名包含 Win32 命名空間中的無效名稱
如果文件名中包含無效的名稱,則可能無法刪除文件 (例如,文件名的尾部空格或尾隨句點,或者文件名僅由一個空格) 組成。 若要解決此問題,請使用適當的內部語法的工具刪除該文件。 您可以使用 "\\?\"
某些工具的語法對這些文件進行操作,例如:
del "\\?\c:\<path_to_file_that contains a trailing space.txt>"
此問題的原因與 原因 4類似。 但是,如果使用典型的 Win32 語法打開名稱中有尾部空格或尾部句點的文件,則在打開實際文件之前,將去除尾部空格或句點。 因此,如果在名為 AFile.txt 的同一文件夾中有兩個文件,並且 AFile.txt (請注意文件名后面的空格) 之后,如果您嘗試使用標准 Win32 調用打開第二個文件,則打開的是第一個文件。 同樣,如果文件的名稱只是一個空格字符,並且您嘗試使用標准 Win32 調用打開它,則打開的是文件的父文件夾。 在這種情況下,如果您嘗試更改這些文件的安全設置,則可能無法執行此操作,否則可能會意外更改不同文件的設置。 如果出現這種情況,您可能會認為您對實際具有限制性 ACL 的文件具有權限。
原因的組合
有時,您可能會遇到這些原因的組合,這會使刪除文件的過程更加復雜。 例如,如果以計算機管理員的身份登錄,則可能會遇到 原因 1 的組合 (您沒有刪除文件的權限) 並 導致 5 (文件名包含一個尾部字符,該字符會導致文件訪問被重定向到其他或不存在的文件) 並且您可能無法刪除該文件。 如果嘗試通過獲取文件所有權並添加權限來解決 原因 1 ,則仍可能無法刪除該文件,因為由於 原因 6,用戶界面中的 ACL 編輯器無法訪問相應的文件。
在這種情況下,可以將 Subinacl 實用程序與 (交換機結合使用,該 /onlyfile
實用程序將包含在資源工具包中,) 用於更改在其他情況下無法訪問的文件的所有權和權限,例如:
subinacl /onlyfile "\\?\c:\<path_to_problem_file>" /setowner= domain\administrator /grant= domain\administrator=F
備注
此命令是一個命令行,為便於閱讀,已將其換行。
此示例命令行修改 C:\<path_to_problem_file>
包含尾隨空格的文件,以便 domain\administrator 帳戶是文件的所有者,並且此帳戶對該文件具有完全控制。 您現在可以使用具有相同語法的 Del 命令刪除此文件 "\\?\"
。
Windows 對長路徑名文件的限制
眾所周知,微軟的文件系統經歷了 fat->fat32->NTFS 的技術變革。且不論安全和文件組織方式上的革新,單就文件名而言,已經從古老的 DOS 8.3 文件格式(僅支持最長 8 個字符的文件名和 3 個字符的后綴名)轉變為可以支持長達 255 個字符的文件名。而對於路徑長度,NTFS 也已經支持長達 32768 個字符的路徑名。
然而,Windows 操作系統並沒有完全放開路徑名長度的限制,在 windef.h 中,可以找到如下的宏:
1 |
|
事實上,所有的 Windows API 都遵循這個限制。因此,每當我們試圖更改某一文件的文件名時,當輸入的文件名長度 ( 全路徑 ) 到達一定限度時,雖然文件名本身還未達到 255 個字符的限制,但是任何輸入將不再被接受,這其實正是由於操作系統不允許 260 個字符(byte)的文件全路徑。
實際應用中,這種 260 個字符的全路徑的限制給應用開發帶來了很大的不便。試想如下應用:我們希望給應用服務器增加一個本地 cache 的功能,該功能可以把遠程服務器上的文件留下一個本地的副本。一個合理的實現可以把 url 映射為文件名,當 url 很長時,cache 文件的長度也會很長。當文件名長度超過 255,我們可以把映射文件名的前 255 個字符作為目錄名稱。但是,我們仍然無法解決 260 個字符的全路徑限制。另外,如果一個應用軟件的目錄結構過深,很容易出現某些文件名長度(含路徑)超過 260 個字符,並因此造成安裝或刪除的失敗。總而言之,該限制給我們的開發測試工作帶來了諸多不便。
對於一些網絡服務器,往往需要將 Java 代碼用於上層邏輯控制 / 事務處理的開發,同時將 C/C++ 用於底層核心功能的實現。為此,我們研究了這兩種程序語言對長路徑名文件的支持情況。其中,對於 Java,比較了兩個常用版本 1.4 和 5.0 對長路徑支持的差異性;對於 C/C++ 語言的局限性,提出了我們的解決方法。
實驗環境 :
操作系統: Windows xp
文件系統: NTFS 文件系統
Java 編譯環境: IBM JDK 1.4.2 以及 IBM JDK 5.0
C++ 編譯環境: VC.net
在 Java 中使用長路徑名文件
Java 語言並不需要對長路徑名文件進行特殊的處理,就可以支持長路徑名文件的創建、讀寫和刪除操作等基本操作。但是,JDK 1.4.2 和 JDK 5.0 在長路徑的支持上是不同的,JDK 1.4.2 並不是完全支持所有的長路徑名文件操作,比如訪問文件屬性的操作是不支持的。我們設計了如下代碼來驗證 JDK 1.4.2 和 JDK 5.0 對長路徑名文件支持的區別。
清單 1. 對長路徑名文件操作的 Java 實驗代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
|
清單 2. 使用 ibm-java2-sdk-142 的結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
從實驗結果來看,JDK 1.4.2 得到了該長路徑名文件的內容,因此,對於該長路徑名文件的創建以及讀寫操作都是支持的。但是對比下文使用 JDK 5.0 的結果,可以看到,所有對於文件屬性的判斷都是錯誤的,同時,重命名的操作也無法實現。更為重要的是,JDK 1.4.2 存在着一個很致命的問題,即方法 File.exists()
是失效的。通常,在刪除文件前,需要調用該方法判斷文件是否存在,對於 JDK 1.4.2,如果直接去刪除一個不知道是否存在的文件,就會存在比較大的風險。因此,JDK 1.4.2 在 Windows 平台對長路徑名文件的操作只是有限的支持,使用的時候,一定要注意。
清單 3. 使用 ibm-java2-sdk-50 的結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
從實驗中可以清楚的看到,在版本 JDK 5.0 中,所有的文件操作(新建、讀寫、屬性操作、重命名、刪除等)都能夠得到正確的處理。使用 JDK 5.0 就可以完全不用擔心長路徑名文件的使用問題。
在 C/C++ 中使用長路徑名文件
相對於 JDK 5.0 不需要任何改動就可以支持長路徑名文件,在 C/C++ 中使用超過 260 個字符的路徑長度的文件,會復雜得多。下面介紹兩種支持長路徑名文件的方法。
方法一:使用 Unicode 版本的 API
從微軟官方網站 Path Field Limits,可以查到,使用 Unicode 版本的 API,對於使用 NTFS 文件系統的 Windows NT 4.0, Windows 2000, Windows XP Home Edition, Windows XP Professional 和 Windows Server 2003 操作系統,可以支持 32768 字節的文件路徑長度。同時,路徑名必須使用 \\?\ 的前綴。依照這個思路,我們設計了實驗。
清單 4. 對長路徑名文件操作的 C 的示例代碼(Unicode API)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
使用如上的方法,我們可以拷貝某長路徑名的文件到當前文件夾中。從試驗結果看,該方法是有效的。但是,由於該方法要求系統使用 Unicode 的 API,同時需要更改路徑名稱以及編碼方式。因此,對於一個已經存在的系統,由於需要改變所有文件操作相關的 API,因此改動將會很大。
方法二:創建 8.3 格式的短路徑名
對於每一個長路徑名,都有一個 8.3 格式(8 個字符的文件名和 3 個字符的后綴名)的短路徑名與其相對應,任意的文件夾或者文件名都可以映射成一個 8 字符的文件名(A~B),其中 A 是文件名前綴,B 是表示字母序的順序。操作系統可以保證這樣的映射是一對一的,只要使用 GetShortPathName()
將長路徑名轉成相應的短路徑名,就可以進行對該文件進行普通的文件操作。同時,在任何時候都可以用函數 GetLongPathName()
把 8.3 格式的短路徑名恢復成初始的長路徑名。
如 GetShortPathName Function 敘述,我們需要一個 Unicode 版本的 API,同時在路徑名前加上 \\?\ 的前綴,才能實現長短路徑名間的切換。但從實驗來看,即使不使用 Unicode 的 API,依然可以實現上述功能。
清單 4. 對長路徑名文件操作的 c 的示例代碼(ShortPath)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
經過上述的代碼,超過 MAX_PATH
限制的路徑名都可以轉變成一個 8.3 格式的短路徑名,可以把這個文件名 (shortPath)
作為后續文件操作函數的參數。這種情況下,對於該文件的所有操作都可以被支持了。我們用這種縮短路徑名長度的方式解決了長路徑名文件的操作問題。
結束語
本文首先列出了不同的 JDK 版本在 Windows 操作系統上對於長路徑名文件處理的區別,同時指出了 JDK 5.0 開始才完全支持長路徑名;在第二部分中給出了兩種支持長路徑名文件的 C/C++ 編程方法。使用上文中的任一方法,我們都可以實現對長路徑名文件的操作,這將在很大程度上方便我們的開發工作,解決在 Windows 平台上標准 API 函數對長路徑名文件支持的局限性問題。
聲明
以上實驗代碼僅在 Windows XP 操作系統和 VC.NET 編譯環境中測試通過 , 作者不對其提供任何種類的保證。如果有任何問題 , 歡迎來信與作者討論。