2

从名称很长的文件访问备用 ntfs 流时遇到了一些麻烦(更多的MAX_PATH字符,根据this使用 "\\?\" 前缀创建)。我第一次认为这是我的代码错误,但后来我尝试了一个 cmd 命令:

more < "\\?\c:\!!!长长长长长长长长长长长长长长长长长长长长长长长长长长长长long long long long long long long long long long long long 文件名!!!.png:streamname"

它失败并显示找不到文件的错误。该文件存在并且可以读取其内容,但我无法访问读取和写入所需的流。我不希望我的软件无法使用长文件名,因此我正在寻找针对这种情况的任何解决方法。

我知道我可以使用BackupRead 功能,但我不确定这个解决方案是否可以快速处理大文件并且它在 2000 年不起作用。

GetShortPathName 给了我同样的失败结果,还有其他可以缩短文件名的 API 吗?我真的不想使用带有短文件名的临时连接来执行此操作。有什么想法吗?

4

1 回答 1

6

正如非常有用的页面CreateFile所说,引用lpFileName指定文件名的参数:

在此函数的 ANSI 版本中,名称仅限于 MAX_PATH 字符。要将此限制扩展到 32,767 个宽字符,请调用函数的 Unicode 版本并在路径前添加“\?\”。

由于您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 个字符,而且我们使用花哨的\\?\语法让我们指定非常长的路径。正确的?

嗯……有点。MSDN 页面上的CreateFile链接指向非常有用的名为Naming Files, Paths and Namespaces的页面。事实上,即使您在问题中链接到该页面。这很有趣,因为它会在你问它之前回答你的问题:

Windows API 有许多函数也有 Unicode 版本,以允许最大总路径长度为 32,767 个字符的扩展长度路径。这种类型的路径由 由反斜杠分隔的组件组成,每个组件都达到 GetVolumeInformation 函数的 lpMaximumComponentLength 参数中返回的值(该值通常为 255 个字符)。要指定扩展长度的路径,请使用“\?\”前缀。例如,“\?\D:\非常长的路径”。

因此,尽管路径本身可能有 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 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元朗文件名!!!.png:流名

快速测试显示,这是 264 个字符长。毫不奇怪,264 大于 255。

于 2013-06-04T22:35:27.120 回答