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

Posted

技术标签:

【中文标题】我应该处理超过 MAX_PATH 的文件吗?【英文标题】:Should I deal with files longer than MAX_PATH? 【发布时间】:2011-02-19 00:39:38 【问题描述】:

刚刚有一个有趣的案例。

我的软件报告了由于路径长度超过 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 托管驱动器上的一个文件。

所以我的问题是这样的。我应该关心吗?

我不是说可以我处理长路径,我问应该我。是的,我知道“\?\”unicode破解一些 Win32 API,但似乎这种破解并非没有风险(因为它改变了 API 解析路径的方式),而且并非所有 API 都支持。

无论如何,让我陈述一下我的立场/主张:

    首先,用户能够打破此限制的唯一方法可能是她使用的应用程序使用了特殊的 Unicode hack。这是一个 PDF 文件,所以她使用的 PDF 工具可能使用了这个 hack。 我试图重现这一点(通过使用 unicode hack)并进行了实验。我发现虽然该文件出现在资源管理器中,但我对此无能为力。我无法打开它,我无法选择“属性”(Windows 7)。其他常用应用无法打开该文件(例如 IE、Firefox、记事本)。 Explorer 也不会让我创建太长的文件/目录 - 它只是拒绝。命令行工具 cmd.exe 同上。

所以基本上,人们可以这样看:rouge 工具允许用户创建许多 Windows(例如资源管理器)无法访问的文件。我可以认为我不应该处理这个问题。

(顺便说一句,这不是对短最大路径长度的投票:我认为 260 个字符是个笑话,我只是说如果 Windows shell 和某些 API 不能处理 > 260 那么我为什么要这样做?)。

那么,这是一个公平的观点吗?我应该说“不是我的问题”吗?

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

【问题讨论】:

创建一个名称过长的文件很容易:只需将其中一个祖先目录重命名为足够长以使文件濒临崩溃。在您的示例中:rename "C:\Documents and Settings\Bill\New Folder" "Some Stupid FOlder Name". 【参考方案1】:

这不是一个真正的问题。 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 的文件句柄,则可以不受任何限制地使用hFileReadFileWriteFile 等)使用的所有其他函数。

如果您编写程序,如病毒扫描程序或备份软件或在服务器上运行的一些好的软件,您应该编写程序,以便所有文件操作都支持最多 32K 个字符的文件名,而不是 @987654331 @ 字符。

【讨论】:

您好,感谢您的评论。是的,我意识到这些 API 存在(请参阅我的帖子)。我不认为一个人可以开始使用这个 hack 并期望一切都一帆风顺。例如,\\?\ hack 删除了一些解析。另外,我不清楚 API 的 OUTPUT 是如何受到影响的。对我来说,这次黑客攻击的影响还不够清楚。如果我走这条路,我将不得不做很多测试。您有使用这些 API 的经验吗? @约翰。您误解了“\\?\”的工作方式。这不是 hack!有据可查的方式主要是直接使用 Native Windows NT API(来自 ntdll.dll),如 NtCreateFile 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 年的使用经验。 好的,是的,“hack”可能是错误的术语 :) 但是我要说的是,它不仅仅是替代品。例如,如果您使用“。”,则相对路径将不起作用。或“..”在一条不起作用的路径中。某些 API 还会更改您使用此“功能”的输出 - (例如 GetLongPathName() 将返回包含“\\?\”的路径)。另一方面,很高兴听到您使用此 API 已有 15 年的经验 - 这让我放心了很多。 这是正确答案。举一个简单的例子,将一个包含所有子目录的目录移动到另一个违反 MAX_PATH 限制的目录。您是否应该让所有无法放入 C:\myreallylong\stupid\directoryname\thatiwant\torestore\myoldbackups\tothisannoying\reallylongpath 的文件失败? ;) 将 UNC 路径前缀为 \\?\host\share 不起作用。您必须使用 \\?\UNC\host\share。【参考方案2】:

这一限制已融入到许多用 C 或 C++ 编写的软件中。很多。包括 MSFT 代码,尽管他们一直在削减它。它只是部分 Win32 限制,例如通过 WIN32_FIND_DATA 对文件名(而不是路径)的长度有硬性上限。甚至 .NET 也有 length restrictions 的原因之一。这不会很快消失,Win32 仍然很强大,石器时代的 C 字符串不会消失。

毫无疑问,您的客户不会对此表示同情,可能直到您向他们展示另一个以同样方式失败的程序。但是,请确保您的代码能够可靠地检测到潜在的字符串缓冲区溢出,然后进行合理的诊断。对轰炸堆损坏的程序没有任何同情。

【讨论】:

嗨,汉斯,感谢您的回复。您目前正在帮助我解决几个问题!谢谢!【参考方案3】:

正如您所提到的,许多 Windows Shell 函数仅适用于最大路径为 MAX_PATH。 Windows XP 和我相信 Vista 在嵌套具有长文件名的目录时都会在资源管理器中出现问题。我没有检查过 Windows 7 - 也许他们已经解决了这个问题。不幸的是,这意味着用户很难浏览这些文件。

如果您真的希望支持长路径,您需要检查您在 Shell32.dll 中使用的任何函数,这些函数采用路径以确保它们支持长路径。对于那些不使用的人,您必须使用 Kernel32 函数自己编写它们。

如果您决定使用 Shell32 并限制为 MAX_PATH,建议您编写代码以支持长文件路径。如果 Microsoft 以后更改 Shell32(或创建替代方案),您将能够更好地添加对它们的支持。

只是为了给问题添加另外几个维度,请记住文件名是 UTF-16,您可能会遇到可能区分大小写的非 NTFS 或 FAT 文件系统!

【讨论】:

是的,Windows 7 的外壳还是一样的。它不仅可以防止您创建文件/文件夹的时间过长,而且如果它碰巧找到一个存在的文件/文件夹,您将无法对其进行任何操作(甚至无法删除它!) @John 感谢您的检查,很高兴知道 7 的能力,尽管令人失望的是它受到同样的限制。【参考方案4】:

您自己的 API 不应硬编码路径长度的固定限制(或任何其他硬限制);但是,您不应该为了完成某些任务而违反系统 API 的先决条件。恕我直言,Windows 限制路径名长度的事实是荒谬的,应该被视为一个错误。也就是说,不,我建议您不要尝试使用除文档之外的各种系统 API,即使这会导致某些不良行为,例如限制最大路径长度。所以,简而言之,你的观点是完全公平的;如果操作系统不支持它,那么操作系统不支持它。也就是说,您可能希望向用户说明这是 Windows 的限制,而不是您自己的代码。

【讨论】:

【参考方案5】:

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

例子:

“C:\My veeeeeeeeeeeeeeeeeeeeeery looooooooooooooooooong 文件夹”可以共享为“数据”。然后,假设 M: 映射到 \\computer\data,用户可以通过 UNC 路径 \\computer\data 或(甚至更短)通过驱动器号 (M:\) 访问该文件夹。

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

【讨论】:

【参考方案6】:

路径通常可以大于 260,一个例子是当符号链接被嵌套并且有时甚至是故意重复时。我认为程序员应该考虑他们是否希望他们的程序处理这些疯狂的大路径。 IMO,260 有足够的空间,但那只是我。我的答案是:

如果您必须如此深入地问自己是否要突破 260 个字符的限制,那么这可能就是您应该做的。当我们即将做一些我们不确定的事情时,我们经常会寻求确认......

我认为 API 中任何地方的最大路径长度约为 32k,但这取决于您。回到过去,这是一个相当大的变化(整个内存段的一半!天哪!)但现在,在我们生活的段透明寻址环境中,所有内存都堆放在 32k 的平面上没什么……除非您使用一些需要大量其他字符等的花哨的 unicode 语言,否则 AFAIK 路径不需要那么长。我们可以整天谈论这个,但您明白了。我希望这会有所帮助......还是伤害?

【讨论】:

【参考方案7】:

我正在做一些 C 编程,我正在寻找一种方法来获得给定文件名的最大长度,在搜索 MAX_PATH 之后,我偶然发现了这个线程,在对这个问题进行了一些思考之后,在阅读了关于这个的 cmets线程我得出了以下结论。

所以我知道 NTFS 支持最长 32.767 个字符的文件名,但是,据了解,FAT16 仅支持 11 个字符的文件名,8 + 3,因此实际上操作系统应该具有我们的程序可以调用的函数来确定最大文件名大小,仅仅是因为所有文件系统都有不同的限制,包括文件名的长度。

所以最终的结论必须是,由于我们这些开发人员不知道数据将存储在哪个文件系统中,因此唯一的解决方案必须是尝试和错误方法。

【讨论】:

【参考方案8】:

严格来说不是对您的具体问题的回答,但它可能会帮助那些确实需要处理长文件名的人。

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

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 个字符)。通常你会遇到 标准 .NET 库发生 System.IO.PathTooLongException 错误。

【讨论】:

以上是关于我应该处理超过 MAX_PATH 的文件吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该处理 X509Certificate2 吗?

REST API 的验收测试 - 我应该处理所有情况吗?

在我使用完服务后,我应该处理服务(层)类吗?

第二次创建peerconeection WebRTC时出现问题(轨道已经存在一个发件人。),我应该处理任何想法

我应该在请求中处理意外的 json 字段吗?

服务器或客户端在发送/接收日期时应该处理时区吗?