DeleteFile() 失败但文件存在(文件名很长)

DeleteFile() failing but the file is there (very long file name)

我正在编写一个有错误的备份程序。使用调试器单步执行代码,我发现删除文件时出错。

我使用 CFileFind 来定位文件,我使用 CFileFind::GetFilePath() 来获取完整路径名。

CFileFind find;
BOOL bContinue = find.FindFile(AppendPath(lpszPath, _T("*")));
while (bContinue)
{
    bContinue = find.FindNextFile();
    if (!find.IsDirectory())
    {
        if (find.IsReadOnly())
            ClearReadOnlyAttribute(find);
        if (!::DeleteFile(find.GetFilePath()))
            return false;
    }
}

DeleteFile() 返回 FALSEGetLastError() 返回 3 (ERROR_PATH_NOT_FOUND),在其他情况下返回 2 (ERROR_FILE_NOT_FOUND)。

如您所见,我首先尝试删除已设置的只读属性;但是,我可以看到该文件存在并且它没有只读属性。

需要注意的一点是文件名很长。这段代码实际上已经过测试并且可以很好地处理较短的文件名。在这种情况下,find.GetFilePath() returns:

\Readyshare\USB 3\Backups\DRIVEZ_BACKUP\Stacey\Backup 0001\Music\TO BE DELETED\iTunes\iTunes Media\Music\Dave Matthews Band\Away from the World (Deluxe Version)\Away from the World (Deluxe Version.itlp\audio\DaveMatthewsBand_AwayFromTheWorld_backgroundaudio.m4a

这看起来是正确的。如果我将文件名以外的所有内容复制到 Windows Explorer 中,它会显示该文件夹。该文件存在于该文件夹中。

有谁知道为什么 DeleteFile() 会告诉我路径或文件不存在,而实际上它存在?

更新:

根据 Bruno Ferreira 的回答,我通过以下方法 运行 我的文件名。 (对于旧的 CString 样式代码,我很抱歉,我正在更新一个旧的 MFC 程序。)

CString CBackupWorker::ConvertToExtendedLengthPath(LPCTSTR pszPath)
{
    CString s(pszPath);

    if (s.GetLength() >= MAX_PATH)
    {
        if (::isalpha(s[0]) && s[1] == ':')
        {
            s.Insert(0, _T("\\?\"));
        }
        else if (s[0] == '\' && s[1] == '\')
        {
            s.Delete(0, 2);
            s.Insert(0, _T("\\\?\UNC\"));
        }
    }
    return s;
}

如代码所示,如​​果文件名超过 MAX_PATH,则会在前面加上适当的前缀。根据路径是否指定网络路径,采取步骤附加适当的前缀。

我不知道为什么要把它搞得这么乱。如果 Windows 允许您指定更长的名称,我真的看不到向后兼容性问题。在 Windows 10 上,有一个您可以更改的注册表设置,这样就不需要这些废话了。但是,当然,我不想将我的软件限制为仅 Windows 10.

的调整版本

来自MSDN

Parameters

lpFileName [in] The name of the file to be deleted. 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. For more information, see Naming a File.

基本上,您应该为本地路径调用 DeleteFileW 前缀 \?\,为远程路径调用 \?\UNC\,如下所示:

CFileFind find;
BOOL bContinue = find.FindFile(AppendPath(lpszPath, _T("*")));
while (bContinue)
{
    bContinue = find.FindNextFile();
    if (!find.IsDirectory())
    {
        if (find.IsReadOnly())
            ClearReadOnlyAttribute(find);

        CString path = find.GetFilePath();
        if (path.GetLength() >= MAX_PATH)
        {
            if (PathIsUNC(path)) {
                path.TrimLeft(_T("\"));
                path.Insert(0, _T("\\?\UNC\"));
            }
            else
                path.Insert(0, _T("\\?\"));
        }

        if (!::DeleteFileW(path))
            return false;
    }
}