在很多应用中经常都要操作文件的,比如递归/非递归删除文件(夹),拷贝文件夹等,在QtCreator中有一个辅助类完成了这些常用的操作FileUtils,在Utils-libs当中。它实现了以下四个操作
static bool removeRecursively(const QString &filePath, QString *error = 0);
static bool copyRecursively(const QString &srcFilePath,
const QString &tgtFilePath, QString *error = 0);
static bool isFileNewerThan(const QString &filePath,
const QDateTime &timeStamp);
static QString resolveSymlinks(const QString &path);
下面分别解释一下它们的实现。
bool FileUtils::removeRecursively(const QString &filePath, QString *error)
{
QFileInfo fileInfo(filePath);//提供系统独立的文件信息,文件名、路径、权限、文件夹(或快捷方式)等。
//如果不存在该路径,并且该路径也不是快捷方式,就不用删除了
if (!fileInfo.exists() && !fileInfo.isSymLink())
return true;
//设置文件的访问权限(添加用户可写权限)
QFile::setPermissions(filePath, fileInfo.permissions() | QFile::WriteUser);
if (fileInfo.isDir())//指定路径是文件夹(或者通过快捷方式链接到一个文件夹)
{
QDir dir(filePath);
dir = dir.canonicalPath();//去掉一些不必要的路径信息,返回绝对路径(返回快捷方式的目标路径)
if (dir.isRoot())//不能删除根目录(C:,D:...)
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils",
"Refusing to remove root directory.");
}
return false;
}
//不能删除home(C:/Documents and Settings/Username)
if (dir.path() == QDir::home().canonicalPath())
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils",
"Refusing to remove your home directory.");
}
return false;
}
//除了..和.之外的文件夹,文件、快捷方式、隐藏文件、系统文件,
//这里返回的只有名字,不是完整路径
QStringList fileNames = dir.entryList(QDir::Files
| QDir::Hidden
| QDir::System
| QDir::Dirs
| QDir::NoDotAndDotDot);
foreach (const QString &fileName, fileNames)
{
//递归删除
if (!removeRecursively(filePath + QLatin1Char('/') + fileName, error))
return false;
}
//删除空的文件夹
if (!QDir::root().rmdir(dir.path()))
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove directory '%1'.")
.arg(QDir::toNativeSeparators(filePath));
}
return false;
}
}
else //说明是文件
{
if (!QFile::remove(filePath))
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove file '%1'.")
.arg(QDir::toNativeSeparators(filePath));
}
return false;
}
}
return true;
}
/*!
\fn resolveSymlinks()
\brief 处理快捷方式,iMaxLevel指定最大链接次数
*/
QString FileUtils::resolveSymlinks(const QString &path, const int &iMaxLevel)
{
QFileInfo f(path);
int links = iMaxLevel;
while (links-- && f.isSymLink())
f.setFile(f.symLinkTarget());
if (links <= 0)
return QString();
return f.filePath();
}
bool FileUtils::copyRecursively(const QString &srcFilePath, const QString &tgtFilePath, QString *error)
{
QFileInfo srcFileInfo(srcFilePath);
if (srcFileInfo.isDir())//是文件夹,应该先创建文件夹,然后拷贝里面文件
{
QDir targetDir(tgtFilePath);
targetDir.cdUp();
//目标文件夹不能存在
if (!targetDir.mkdir(QFileInfo(tgtFilePath).fileName()))
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to create directory '%1'.")
.arg(QDir::toNativeSeparators(tgtFilePath));
return false;
}
}
QDir sourceDir(srcFilePath);
QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
//深度优先遍历即可
foreach (const QString &fileName, fileNames)
{
const QString newSrcFilePath
= srcFilePath + QLatin1Char('/') + fileName;
const QString newTgtFilePath
= tgtFilePath + QLatin1Char('/') + fileName;
if (!copyRecursively(newSrcFilePath, newTgtFilePath, error))
return false;
}
}
else
{
if (!QFile::copy(srcFilePath, tgtFilePath))
{
if (error)
{
*error = QCoreApplication::translate("Utils::FileUtils", "Could not copy file '%1' to '%2'.")
.arg(QDir::toNativeSeparators(srcFilePath),
QDir::toNativeSeparators(tgtFilePath));
}
return false;
}
}
return true;
}
/*!
* \brief FileUtils::isFileNewerThan
* 比较文件或文件夹是否比某个时间新,如果filePath是文件夹,那么它里面有一个文件比timeStamp新,
* 就返回真
*/
bool FileUtils::isFileNewerThan(const QString &filePath, const QDateTime &timeStamp)
{
QFileInfo fileInfo(filePath);
if (!fileInfo.exists())//如果文件不存在,返回false
return false;
if (fileInfo.lastModified() >= timeStamp)//文件修改时间更新
return true;
if (fileInfo.isDir())
{
//这里不包括隐藏文件、快捷方式等系统文件
const QStringList dirContents = QDir(filePath)
.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
foreach (const QString &curFileName, dirContents)
{
const QString curFilePath
= filePath + QLatin1Char('/') + curFileName;
if (isFileNewerThan(curFilePath, timeStamp))
return true;
}
}
return false;
}
上边的isFileNewerThan中代码与源码不太相同,因为我认为当文件路径不存在时,应该返回false的。