访问ntfs流以获取非常长的文件名失败

时间:2013-06-04 21:28:29

标签: windows winapi stream ntfs

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

  

更多< “长long长长多长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长多头长long long long long long long long long filename !!!。png:streamname“

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

我知道我可以使用BackupRead function,但我不确定这个解决方案是否可以在大型文件上快速运行,并且在2000年无效。

GetShortPathName给出了相同的失败结果,是否还有其他可以缩短文件名的API?我真的不想使用短文件名的临时联结。 有什么想法吗?

1 个答案:

答案 0 :(得分: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个字符,我们使用花哨的\\?\语法让我们指定 reeeeeally 长路径。正确?

好吧......好吧。 CreateFile上的MSDN页面链接到标题为Naming Files, Paths and Namespaces的非常有用的页面。事实上,即使您在问题中链接到该页面。这很有意思,因为在您提出问题之前它会回答您的问题:

  

Windows API具有许多也具有Unicode版本的函数   允许一个扩展长度的路径,最大总路径长度为   32,767个字符。此类路径由组件组成   用反斜杠分隔,每个直到返回的值   GetVolumeInformation的lpMaximumComponentLength参数   function(此值通常为255个字符)。指定一个   扩展长度路径,使用“\?\”前缀。例如,“\?\ D:\ very   漫长的道路“。

因此,虽然路径本身可能是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 filename !!!。png:streamname

快速测试显示这是264个字符长。而264,它应该不足为奇,大于255。