创建工程时,对“临时文件夹删除,然后重建”应该是一个很常用的问题。可是,就是这个常用的删除/递归删除子文件夹,然后重建文件目录的过程,偶尔会出现删不掉的状况。换了两种操作方式,发现都会出这种状况。头疼
通过try-catch异常捕获还是找到了原因,就是文件夹被打开的情况下是没有办法删除的。在资源管理器中打开,即打开此文件夹,在任务管理器中就会显示有此任务,这应该是一个通用问题,不过之前没有注意到。最后还是师傅亲自出马解决了,remove dir by shell operation在文件夹被打开情况下也暴力删除。
总结经验:不管认为多么正确,只要有bug就一定是有错误的:最后只能分为解决了错误和解决不了错误两种;一定要再好好看看捕获异常,超有用;师傅就是师傅,经验老道,还是很厉害的。
1. Qt: QDir类递归删除文件
具体操作:从最底层一层一层的向上删除:QDir::rmdir,QFile::remove;创建:mkdir
注意事项:QDir::rmdir要求当前dir必须为空,且不能处于被占用状态
头文件:#include <QDir> #include <QFile>
// 删除文件结构
bool rmdir(const QString &dirPath)
{
QDir curDir(dirPath);
if (!curDir.exists())
return true;
bool error = false;
QStringList entries = curDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
for (QList<QString>::iterator entry = entries.begin(); entry != entries.end(); ++entry)
{
QString filePath = QDir::convertSeparators(dirPath + '/' + *entry);
QFileInfo fileInfo(filePath);
if (fileInfo.isFile() || fileInfo.isSymLink())
{
QFile::setPermissions(filePath, QFile::WriteOwner);
if (!QFile::remove(filePath))
error = true;
}
else if (fileInfo.isDir())
{
if (!removeDir(filePath))
error = true;
}
}
if (!curDir.rmdir(QDir::convertSeparators(dirPath)))
error = true;
return !error;
}
// 创建文件结构
// homeDirPath/project
// homeDirPath/project/work1
// homeDirPath/project/work2
// homeDirPath/project/work1/sub_work1
// homeDirPath/project/work1/sub_work2
QDir curDir(homeDirPath);
if (curDir.mkdir(project))
{
curDir.cd(project);
curDir.mkdir(work1);
curDir.cd(work1);
curDir.mkdir(sub_work1);
curDir.mkdir(sub_work2);
curDir.cdUp();
curDir.mkdir(work2);
}
2. Boost库: filesystem库实现
具体操作:删除:remove(), remove_all(); 创建:create_directory, create_directories
注意事项:
QDir::rmdir要求当前dir必须为空,且不能处于被占用状态
Filesystem库需要system库支持,因此必须先编译system库;filesystem库需要先编译才能使用
头文件:#include <boost/filesystem.hpp>,注意工程配置,添加lib库文件
void filesystem(const char *filePath)
{
boost::filesystem::path ptest(filePath);
// remove dir
try
{
if (boost::filesystem::exists(ptest))
{
if (boost::filesystem::is_empty(ptest))
boost::filesystem::remove(ptest);
else
boost::filesystem::remove_all(ptest);
}
}
catch (boost::filesystem::filesystem_error& e)
{
std::cout << e.path1() << std::endl;
std::cout << e.what() << std::endl;
}
// create path
try
{
boost::filesystem::create_directory(ptest);
boost::filesystem::create_directories(ptest / work1 / sub_work1);
boost::filesystem::create_directories(ptest / work1 / sub_work2);
boost::filesystem::create_directories(ptest / work2);
}
catch (boost::filesystem::filesystem_error& e)
{
std::cout << e.path1() << std::endl;
std::cout << e.what() << std::endl;
}
}
3. Remove Dir by shell operator
具体操作:使用Window API
头文件:#include <windows.h> #include <shobjidl.h>
#define MAX_PATH 200
// using windows api
bool removeDirByShellOp(const QString &dirPath)
{
QString dir(dirPath);
dir.replace('/', '\\');
// convert the folder path to Unicode string
char mbcsPath[MAX_PATH];
strcpy(mbcsPath, dir.toLocal8Bit().constData());
int requiredSize = MultiByteToWideChar(CP_ACP, 0, mbcsPath, -1, NULL, 0);
if (requiredSize == 0)
return false;
TCHAR *wcsPath = new TCHAR[requiredSize];
MultiByteToWideChar(CP_ACP, 0, mbcsPath, -1, wcsPath, requiredSize);
// check if the folder exists
DWORD attrib = GetFileAttributes(wcsPath);
if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY))
{
IFileOperation *fileOp = NULL;
IShellItem *shItem = NULL;
// call shell API to remove the folder
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
HRESULT hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_IFileOperation, (LPVOID*)&fileOp);
if (hr == S_OK)
{
hr = fileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOFX_NOMINIMIZEBOX);
if (hr == S_OK)
{
SHCreateItemFromParsingName(wcsPath, NULL, IID_PPV_ARGS(&shItem));
hr = fileOp->DeleteItems(shItem);
if (hr == S_OK)
hr = fileOp->PerformOperations();
shItem->Release();
}
fileOp->Release();
}
CoUninitialize();
delete[] wcsPath;
return (hr == S_OK);
}
return true;
}