我正在编写一个有错误的备份程序。使用调试器逐步执行代码,我发现删除文件时出错。
我正在使用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。
答案 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;
}
}