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

Seg*_*ero 2 windows winapi ntfs stream

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

更多<"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\long long long long long long long long long long filename !!!.png:streamname"

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

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

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

Nik*_*lis 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;
Run Code Online (Sandbox Code Playgroud)

}

这应该工作得很好.现在,让我们通过添加更多的单词来使文件名更长.同样,请务必正确更新机器上有效内容的路径.

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";
Run Code Online (Sandbox Code Playgroud)

现在已经很久了.它会失败.很奇怪......如果我们检查输出GetLastError()我们会得到ERROR_INVALID_NAME什么给出的?这应该工作,因为它显然不\\?\超过32,767个字符,我们正在使用花哨的语法让我们指定reeeeeally长路径.对?

好吧......有点儿.MSDN页面CreateFile链接到非常有用的页面,命名命名文件,路径和命名空间.事实上,即使您在问题中链接到该页面.这很有趣,因为在您提出问题之前它会回答您的问题:

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

因此,虽然路径本身可能是32,767个字符长,但路径的单个组件(即"部分")可能不会超过文件系统允许的最大值.实际上,如果您试图找出NTFS报告的最大组件长度,它将是255.

因此文件名是单个组件,单个组件不能超过255个字符.您指定的文件名是:

!!!长长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长加长.文件名!PNG:streamName中

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