问题描述
上下文:
我有一个应用程序,可以使用QDirIterator
在目录中搜索文件,过滤并复制特定文件。
问题:
使用QDirIterator::next()的结果,我使用有效的QFile::exists(QString)确保文件存在(作为不必要的安全措施)。
GetLastError()报告ERROR_FILE_NOT_FOUND错误:
ERROR_FILE_NOT_FOUND
2(0x2)
系统找不到指定的文件。
// QString src (src file location),dst (destination file location)
QFileInfo fi(m_src);
QString dir = fi.dir().path();
const wchar_t* dirC = toLPCWSTR(dir);
QString src = QString(m_src).replace("/","\\");
QString dst = QString(m_src).replace("/","\\");
const wchar_t* localC_src = toLPCWSTR(src);
const wchar_t* localC_dst = toLPCWSTR(dst);
auto rc = copyFileExW(localC_src,localC_dst,&backupmanager::copyProgress,this,&bStopBackup,0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x32
bool dirExist = DirExists(dirC); // true
bool fileExists = FileExists(localC_src); // true
printWarning(TAG,QString("File copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#Failedcopy: Windows file exists but copy Failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
// =================================================
// < ------------------------------------- This is gets triggered
// =================================================
qDebug() << "#Failedcopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#Failedcopy: Windows file copy Failed outright" << src;
}
}
// ...
} else {
// success
}
问题:
对我来说没有意义的是,为什么QFile::exists(String)
报告FilecopyExW
找到的文件说系统找不到指定的文件。我想念什么?
调试器图片:
完整代码实现:
static QString toString(HRESULT hr)
{
_com_error err{hr};
const TCHAR* lastError = err.ErrorMessage();
return QStringLiteral("Error 0x%1: %2").arg((quint32)hr,8,16,Qlatin1Char('0'))
.arg(lastError);
}
static QString getLastErrorMsg()
{
DWORD lastError = GetLastError();
QString s = toString(HRESULT_FROM_WIN32(lastError));
return s;
}
BOOL FileExists(LPCWSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
// not used
static const wchar_t* toLPCWSTR(QString s)
{
std::wstring dstWString = s.toStdWString();
const wchar_t* localC_src = dstWString.c_str();
return localC_src;
}
static bool DirExists(LPCWSTR szPath)
{
DWORD ftyp = GetFileAttributes(szPath);
if (ftyp == INVALID_FILE_ATTRIBUTES)
return false; //something is wrong with your path!
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
return true; // this is a directory!
return false; // this is not a directory!
}
BackupResult backupmanager::copyFile(QString m_src,QString m_dst)
{
QFileInfo fi(m_src);
QString dir = fi.dir().path();
const wchar_t* dirC = toLPCWSTR(dir);
QString src = QString(m_src).replace("/","\\");
const wchar_t* localC_src = toLPCWSTR(src);
const wchar_t* localC_dst = toLPCWSTR(dst);
// c-style casts
// LPCWSTR localC_src = (LPCWSTR) src.utf16();
// LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
// LPCWSTR dirC = (LPCWSTR) dir.utf16();
auto rc = copyFileExW(localC_src,0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x2 (2)
bool dirExist = DirExists(dirC); // false
bool fileExists = FileExists(localC_src); // false
printWarning(TAG,QString("File copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#Failedcopy: Windows file exists but copy Failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
qDebug() << "#Failedcopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#Failedcopy: Windows file copy Failed outright" << src;
}
}
#endif
// copy Failed
return BackupResult::IOError;
}
// copy success
return BackupResult::Success;
}
更新:
如@john的评论中所述,目标文件指向源文件时出现了一个问题,该文件显然无法正常工作。
已解决此问题,这突出显示了另一个错误ERROR_INVALID_NAME:
ERROR_INVALID_NAME
123(0x7B)
文件名,目录名或卷标语法不正确。
解决方法
此功能有问题:
// not used
static const wchar_t* toLPCWSTR(QString s)
{
std::wstring dstWString = s.toStdWString();
const wchar_t* localC_src = dstWString.c_str();
return localC_src;
}
您将返回已被解构的字符串的原始指针。
因此,这两行:
const wchar_t* localC_src = toLPCWSTR(src);
const wchar_t* localC_dst = toLPCWSTR(dst);
是不确定的行为,但最可能的结果是localC_src
和localC_dst
指向已释放的内存。
最好在您的内部指针仍被引用的同时保持std::wstring
随处可见
std::wstring strSrc = src.toStdWString();
std::wstring strDst = dst.toStdWString();
const wchar_t* localC_src = strSrc.c_str();
const wchar_t* localC_dst = strDst.c_str();