DeleteFile()失败,但文件在那里(文件名很长)

时间:2017-02-22 21:56:14

标签: c++ windows winapi mfc delete-file

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

我正在使用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()正在返回FALSE,而GetLastError()正在返回3(ERROR_PATH_NOT_FOUND),而在其他情况下则返回2(ERROR_FILE_NOT_FOUND)。

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

需要注意的一点是文件名很长。这段代码实际上经过了测试,并且在较短的文件名下运行良好。在这种情况下,find.GetFilePath()会返回:

  

\\ Readyshare \ USB 3 \ Backups \ DRIVEZ_BACKUP \ Stacey \ Backup 0001 \ Music \ TO BE DELETED \ iTunes \ iTunes Media \ Music \ Dave Matthews Band \远离世界(豪华版)\远离世界( Deluxe Version.itlp \ audio \ DaveMatthewsBand_AwayFromTheWorld_backgroundaudio.m4a

这看起来很正确。如果我将除文件名以外的所有文件复制到Windows资源管理器中,它会显示该文件夹该文件存在于该文件夹中。

有没有人知道为什么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。

1 个答案:

答案 0 :(得分:7)

来自MSDN

  

参数

     

lpFileName [in]要删除的文件的名称。在ANSI中   此函数的版本,名称仅限于MAX_PATH字符。   要将此限制扩展为32,767个宽字符,请调用Unicode   该功能的版本和前置" \\?\"到了路上。更多   信息,请参阅命名文件。

基本上,您应该为本地路径调用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;
    }
}