从名称很长的文件(超过 MAX_PATH
个字符长,根据 this 使用“\\?\”前缀创建)访问备用 ntfs 流时遇到一点问题.我第一次认为这是我的代码错误,但后来我尝试了一个 cmd 命令:
more < "\\?\c:\!!!Long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long filename!!!.png:streamname"
它失败并显示找不到文件的错误。该文件存在并且可以读取其内容,但我无法访问读取和写入所需的流。 我不希望我的软件无法处理长文件名,因此我正在寻找针对这种情况的任何解决方法。
我知道我可以使用 BackupRead function , 但我不确定这个解决方案是否可以在大文件上快速运行并且它在 2000 中不起作用。
GetShortPathName 给了我同样的失败结果,还有其他可以缩短文件名的 API 吗?我真的不想使用短文件名的临时连接来执行此操作。 有什么想法吗?
最佳答案
作为 CreateFile
上非常有用的页面指的是指定文件名的 lpFileName
参数:
In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\?\" to the path.
由于您正在考虑 BackupRead
,显然您希望以编程方式访问此流。如果是这样,请以编程方式进行测试。从命令提示符尝试所有这些操作是胡说八道,除了从命令提示符执行此类操作的能力之外不会建立任何东西。
考虑到这一点,让我们试试这个简单的程序——删除样板代码:
#include "stdafx.h"
int APIENTRY _tWinMain(HINSTANCE,
HINSTANCE,
LPTSTR,
int)
{
/* This is the name of the file that we will try to create. Please note that
* I have hardcoded the path to my user directory (C:\Users\nikb), and since
* it's unlikely that path exists on your computer, you should probably put
* something there that makes sense.
*/
LPCWSTR lpszFileName = L"\\\\?\\c:\\users\\nikb\\!!!Long long long long "
L"long long long long long long long long long long "
L"long long long long long long long long long long "
L"long long long long long long filename!!!.png:streamname";
HANDLE hFile = CreateFileW(lpszFileName, GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BYTE bBuffer[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'N', 'i', 'k', '!' };
DWORD dwSize = 10;
if(WriteFile(hFile, bBuffer, dwSize, &dwSize, NULL))
::MessageBoxW(GetDesktopWindow(), L"Success", L"WriteFile", MB_OK);
else
::MessageBoxW(GetDesktopWindow(), L"Failure", L"WriteFile", MB_OK);
CloseHandle(hFile);
}
return 0;
这应该可以正常工作。所以现在,让我们通过添加更多的单词来使文件名更长。同样,请务必将路径正确更新为在您的计算机上有效的内容。
LPCWSTR lpszFileName = L"\\\\?\\c:\\users\\nikb\\!!!Long long long long long long long "
L"long long long long long long long long long long long "
L"long long long long long long long long long long long "
L"long long long long long long long long long long long "
L"long long long long long long long long long long long "
L"long long long long long long long long long long long "
L"long long long long long long long long long long long "
L"long long filename!!!.png:streamname";
现在是长。它会失败。奇怪...如果我们检查 GetLastError()
的输出,我们将得到 ERROR_INVALID_NAME
那是什么原因呢?这应该可行,因为它显然不会超过 32,767 个字符,而且我们正在使用奇特的 \\?\
语法来指定reeeeeally 长路径。对吧?
嗯……有点像。 CreateFile
上的 MSDN 页面链接到标题为 Naming Files, Paths and Namespaces 的非常有用的页面.事实上,即使您在问题中链接到该页面。这很有趣,因为它会在您提出问题之前回答您的问题:
The Windows API has many functions that also have Unicode versions to permit an extended-length path for a maximum total path length of 32,767 characters. This type of path is composed of components separated by backslashes, each up to the value returned in the lpMaximumComponentLength parameter of the GetVolumeInformation function (this value is commonly 255 characters). To specify an extended-length path, use the "\?\" prefix. For example, "\?\D:\very long path".
因此,尽管路径本身可能有 32,767 个字符长,但路径的任何单个组件(即“部分”)都不能超过文件系统允许的最大值。事实上,如果您尝试找出 NTFS 报告的最大组件长度,它将是 255。
所以文件名是单个组件,单个组件不能超过255个字符。您指定的文件名是:
!!!Long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long filename!!!.png:streamname
快速测试显示这是 264 个字符长。毫不奇怪,264 大于 255。
关于windows - 访问非常长的文件名的 ntfs 流失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16927798/