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

Jon*_*ood 1 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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 \远离世界(豪华版)\远离世界(豪华版). itlp \音频\ 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;
}
Run Code Online (Sandbox Code Playgroud)

正如您可以看到的那样,如果文件名超出,则在前面添加适当的前缀MAX_PATH.根据路径是否指定网络路径,采取步骤附加适当的前缀.

我不知道为什么这个令人难以置信的凌乱.如果Windows允许您指定更长的名称,我真的看不到向后兼容性问题.在Windows 10上,您可以更改注册表设置,以便不需要这种废话.但是,当然,我不想将我的软件限制为只调整版本的Windows 10.

Bru*_*ira 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @RbMm来自MSDN:`"\\?\"前缀也可以用于根据通用命名约定(UNC)构造的路径.要使用UNC指定此类路径,请使用"\\?\ UNC \"前缀.例如,"\\?\ UNC\server\share",其中"server"是计算机的名称,"share"是共享文件夹的名称.https://msdn.microsoft.com/pt- BR /库/窗/桌面/ aa365247(v = vs.85)的.aspx (2认同)