我应该处理超过MAX_PATH长度的文件吗?

32

刚遇到一个有意思的案例。

我的软件报告了一个由路径长度超过MAX_PATH引起的故障。

该路径只是我的文档中的一个普通文件,例如:

C:\Documents and Settings\Bill\Some Stupid FOlder Name\A really ridiculously long file thats really very very very..........very long.pdf

总长度为269个字符(MAX_PATH==260)。

用户并没有使用外部硬盘或其他类似设备,这是一个在Windows管理的驱动器上的文件。

所以我的问题是:我应该关注这个问题吗?

我不是在说我可以处理长路径,我在问我是否应该这样做。是的,我知道在一些Win32 API上的“\?\” Unicode hack,但是它似乎有风险(因为它改变了API解析路径的方式),而且也不被所有API支持。

无论如何,让我表述我的立场/观点:

  1. 首先,假设用户能够突破此限制的唯一方法是她使用了特殊的Unicode hack。这是一个PDF文件,所以可能是她使用的PDF工具使用了这个hack。
  2. 我尝试复现了这个问题(使用Unicode hack进行实验)。我发现,虽然文件出现在资源管理器中,但我无法对其进行任何操作。我不能打开它,我不能选择“属性”(在Windows 7中),其他常见应用程序也无法打开文件(例如IE、Firefox、记事本)。资源管理器也不允许我创建过长的文件/目录-它会拒绝。命令行工具cmd.exe也是如此。

因此,可以这样看待这个问题:一个流氓工具允许用户创建了一个大多数Windows(例如资源管理器)无法访问的文件。我可以认为我不应该处理这个问题。

(顺便说一句,这并不意味着我对短的最大路径长度表示赞同:我认为260个字符是个笑话,我只是在说如果Windows shell和一些API不能处理>260字符,那么我为什么要这样做?)

所以,这种观点是否公正?我应该说“不是我的问题”吗?

更新:刚刚有另一个用户遇到了同样的问题。这次是一个mp3文件。我错过了什么吗?这些用户如何创建违反MAX_PATH规则的文件?


9
创建一个文件名太长的文件非常容易:只需要将其祖先目录之一重命名为足够长以使文件跨过临界点即可。在您的示例中:rename "C:\Documents and Settings\Bill\New Folder" "Some Stupid FOlder Name" - Adrian Pronk
8个回答

12

这不是一个真正的问题。NTFS支持长达32K32,767个宽字符)的文件名。您只需要使用正确的API和正确的文件名语法即可。基本规则是:文件名应以'\\?\'开头(参见http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx),例如\\?\C:\Temp。您可以在UNC中使用相同的语法:\\?\UNC\Server\share\Path。重要的是要了解,您只能使用一小部分API函数。例如,请查看MSDN函数描述

CreateFile
CreateDirectory 
MoveFile

等等之类的文本

你会发现这样的文字:

在该函数的 ANSI 版本中,名称仅限于 MAX_PATH 字符。要将此限制扩展到 32,767 个宽字符,请调用该函数的 Unicode 版本并在路径前面添加 "\?\"。有关详细信息,请参阅命名文件。

你可以安全地使用这些功能。如果你已经从 CreateFile 获得了一个文件句柄,那么你可以使用所有其他使用了 hFile 的函数(如 ReadFileWriteFile 等)而没有任何限制。

如果你编写像病毒扫描程序、备份软件或一些运行在服务器上的好软件之类的程序,你应该编写你的程序以支持最多长达32K个字符的文件名,而不是 MAX_PATH 字符。


4
谢谢您的留言。是的,我意识到这些API存在(请看我的帖子)。我认为不能指望使用这个技巧一切都会顺利。例如,“\?\” 技巧会删除一些解析。此外,我不清楚这些API的输出会受到什么影响。对于我来说,这种影响还不够清晰。如果我选择这条路,我需要做很多测试。您有使用这些API的经验吗? - John
7
@John。您误解了“\?\”的使用方式。这不是一个黑客技巧!这是一种经过充分记录的方式,主要用于直接处理本机Windows NT API(来自ntdll.dll),例如NtCreateFile http://msdn.microsoft.com/en-us/library/bb432380%28VS.85%29.aspx。如果您使用此功能,您将**不会减少安全性,但只会减少舒适度**。大多数Windows API来自16位Windows 3.0时代,并具有MAX_PATH限制。本机Windows NT API(来自ntdll.dll)主要用于驱动程序开发。因此,“\?\”的使用是安全的。我在使用此功能方面拥有15年以上的经验。 - Oleg
4
好的,是的,“hack”可能不是正确的术语 :) 然而,我的意思是它不仅仅是一个替代品。例如,相对路径将无法工作,如果您在路径中使用“.”或“..”,它也无法工作。如果使用此“特性”,某些API的输出也会发生更改-(例如,GetLongPathName()将返回包括“\?\”的路径)。另一方面,很高兴听到您已经有15年的使用此API的经验-这让我放心了很多。 - John
1
这是正确的答案。以将带有所有子项的目录移动到与MAX_PATH限制相冲突的另一个目录为简单案例。你应该只是放弃那些无法适应C:\myreallylong\stupid\directoryname\thatiwant\torestore\myoldbackups\tothisannoying\reallylongpath的文件吗? ;) - GalacticJello
2
在编程中,将UNC路径前缀为“\?\host\share”是无效的。您必须使用“\?\UNC\host\share”。 - Ilya
@Ilya:感谢您修复了小费错误。我很高兴仍然有人阅读旧帖子。:-)。我引用4年前的MSDN文档链接(http://msdn.microsoft.com/en-us/library/aa365247(v=VS.85).aspx),它仍然有效。其中包含许多其他有用的名称(\\.\CdRomX, \\.C:, \\.\PhysicalDiskX, \\?\GLOBALROOT等)。我只是想指出突破MAX_PATH限制的可能性,并展示使用方法确实很容易。 - Oleg

10

这种限制是在许多用C或C++编写的软件中固有的,包括微软的代码,尽管他们一直在改进它。 它只是Win32限制的一部分,例如通过WIN32_FIND_DATA它仍然对文件名(而不是路径)长度有一个硬性的上限。 这也是即使.NET存在长度限制的原因之一。 Win32仍然很流行,附带的C字符串也不会消失,这种情况短期内不会发生变化。

毫无疑问,你的客户对此不会感到同情,可能直到你能向他们展示另一个出现相同问题的程序为止。 但请确保您的代码可靠地检测到潜在的字符串缓冲区溢出,并提供合理的诊断。对于由于堆损坏而导致程序崩溃的情况是不会受到同情的。


嗨,汉斯,谢谢你的回复。目前你正在帮我解决几个问题!感谢! - John

6
正如您所提到的,许多Windows Shell函数仅适用于最大长度为MAX_PATH的路径。在嵌套具有长文件名的目录时,Windows XP和Vista都存在Explorer问题。我没有检查Windows 7 - 也许他们已经解决了这个问题。不幸的是,这意味着用户很难浏览这些文件。
如果您真的希望支持长路径,您需要检查Shell32.dll中使用的任何需要路径的函数,以确保它们支持长路径。对于那些不支持的功能,您将不得不使用Kernel32函数自己编写。
如果您决定使用Shell32并受到MAX_PATH限制,则编写支持长文件路径的代码是明智的选择。如果Microsoft稍后更改Shell32(或创建替代品),您将更好地为它们添加支持。
只是为了给问题增加另外两个维度,记住文件名是UTF-16,并且您可能会遇到对大小写敏感的非NTFS或FAT文件系统!

1
是的,Windows 7的外壳仍然是一样的。它不仅可以防止您创建过长的文件/文件夹,而且如果它发现存在一个这样的文件/文件夹,您将无法对其进行任何操作(甚至无法删除!) - John
@John 感谢您的检查,知道 7 的能力是很好的,尽管失望的是它也面临同样的限制。 - Stephen Nutt

5

你自己的API不应该在路径长度(或任何其他硬限制)上硬编码固定限制;然而,为了完成某些任务,你不应该违反系统API的前提条件。我认为,Windows限制路径名称的长度是荒谬的,应该被视为一个错误。也就是说,我建议你不要尝试使用各种系统API,除非按照文档说明,即使这导致某些不希望的行为,比如限制最大路径长度。简而言之,你的观点是完全公正的;如果操作系统不支持它,那么操作系统就不支持它。话虽如此,你可能需要向用户明确说明这是Windows的限制,而不是你自己的代码的限制。


2

即使软件不支持超过MAX_PATH长度的路径,也有一种简单的方法可以创建这些长路径文件:通过文件共享。

例如:

"C:\My veeeeeeeeeeeeeeeeeeeeery looooooooooooooooooong folder" 可以共享为 "data"。用户可以通过UNC路径 \\computer\data 或(更短)驱动器字母(M:\)访问该文件夹,假设 M: 被映射到 \\computer\data。

这种情况经常发生在文件服务器上。


1
我正在进行一些C编程,寻找一种获取给定文件名最大长度的方法,在搜索MAX_PATH后,我偶然发现了这个帖子,并在思考这个问题并阅读了这个帖子的评论之后,得出了以下结论。
我知道NTFS支持长达32,767个字符的文件名,但是据我所知,FAT16仅支持11个字符的文件名(8 + 3),因此,实际上操作系统应该有一个函数,我们的程序可以调用以确定最大文件名大小,因为所有文件系统都具有不同的限制,包括文件名的长度。
因此,最终的结论必须是,由于我们开发人员不知道数据将存储在哪个文件系统中,因此唯一的解决方案必须是尝试和错误的方法。

1

路径通常可以比260更大,一个例子是当符号链接嵌套并重复多次甚至故意这样做时。我认为程序员应该考虑他们是否想要处理这些非常大的路径。在我看来,260已经足够了,但这只是我的看法。我的答案是:

如果你必须深入思考如何突破260个字符的限制,那么你可能就应该这样做。当我们不确定要做某件事情时,我们经常寻求确认...

我认为API中任何地方的最大路径长度约为32k,但这取决于你。在过去,这是一大笔钱(半个内存段!!天哪!),但现在,在我们生活的段透明寻址环境中,所有内存都堆积在一起,32k什么都不是... 据我所知,除非你使用一些需要大量其他字符的花哨的Unicode语言等等,否则路径不需要那么长。我们可以一整天地闲扯,但你懂的。希望这有所帮助...或者伤害?


0

虽然这不是对你具体问题的严格回答,但它可能会帮助那些需要处理长文件名的人。

Delimon库是一个基于.NET Framework 4的库,可在Microsoft TechNet上解决长文件名问题:

Delimon.Win32.I​O Library (V4.0)

它有自己版本的System.IO关键方法。例如,您可以替换:

System.IO.Directory.GetFiles

使用

Delimon.Win32.IO.Directory.GetFiles

这将让您处理长文件和文件夹。

来自网站:

Delimon.Win32.IO替换了System.IO的基本文件功能,并支持长达32,767个字符的文件和文件夹名称。

此库是在.NET Framework 4.0上编写的,可以在x86和x64系统上使用。标准System.IO命名空间的文件和文件夹限制可以处理文件名中有260个字符和文件夹名中有240个字符的文件(MAX_PATH通常配置为260个字符)。通常,您会遇到Standard .NET Library的System.IO.PathTooLongException错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接