123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- #include "fileutils.h"
- #include <QFile>
- #include <QMimeDatabase>
- #include <QDateTime>
- #include <QTemporaryFile>
- #include <QJsonDocument>
- #include <core/exception.h>
- #include <core/global.h>
- #include "pathutils.h"
- using namespace vnotex;
- QByteArray FileUtils::readFile(const QString &p_filePath)
- {
- QFile file(p_filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- Exception::throwOne(Exception::Type::FailToReadFile,
- QString("failed to read file: %1").arg(p_filePath));
- }
- return file.readAll();
- }
- QString FileUtils::readTextFile(const QString &p_filePath)
- {
- QFile file(p_filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- Exception::throwOne(Exception::Type::FailToReadFile,
- QString("failed to read file: %1").arg(p_filePath));
- }
- // TODO: determine the encoding of the text.
- QString text(file.readAll());
- file.close();
- return text;
- }
- QJsonObject FileUtils::readJsonFile(const QString &p_filePath)
- {
- return QJsonDocument::fromJson(readFile(p_filePath)).object();
- }
- void FileUtils::writeFile(const QString &p_filePath, const QByteArray &p_data)
- {
- QFile file(p_filePath);
- if (!file.open(QIODevice::WriteOnly)) {
- Exception::throwOne(Exception::Type::FailToWriteFile,
- QString("failed to write to file: %1").arg(p_filePath));
- }
- file.write(p_data);
- file.close();
- }
- void FileUtils::writeFile(const QString &p_filePath, const QString &p_text)
- {
- QFile file(p_filePath);
- if (!file.open(QIODevice::WriteOnly)) {
- Exception::throwOne(Exception::Type::FailToWriteFile,
- QString("failed to write to file: %1").arg(p_filePath));
- }
- QTextStream stream(&file);
- stream << p_text;
- file.close();
- }
- void FileUtils::writeFile(const QString &p_filePath, const QJsonObject &p_jobj)
- {
- writeFile(p_filePath, QJsonDocument(p_jobj).toJson());
- }
- void FileUtils::renameFile(const QString &p_path, const QString &p_name)
- {
- Q_ASSERT(PathUtils::isLegalFileName(p_name));
- QString newFilePath(PathUtils::concatenateFilePath(PathUtils::parentDirPath(p_path), p_name));
- QFile file(p_path);
- if (!file.exists() || !file.rename(newFilePath)) {
- Exception::throwOne(Exception::Type::FailToRenameFile,
- QString("failed to rename file: %1").arg(p_path));
- }
- }
- bool FileUtils::childExistsCaseInsensitive(const QString &p_dirPath, const QString &p_name)
- {
- QDir dir(p_dirPath);
- if (!dir.exists()) {
- return false;
- }
- auto name = p_name.toLower();
- auto children = dir.entryList(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
- for (const auto &child : children) {
- if (child.toLower() == name) {
- return true;
- }
- }
- return false;
- }
- bool FileUtils::existsCaseInsensitive(const QString &p_path)
- {
- return childExistsCaseInsensitive(PathUtils::parentDirPath(p_path), PathUtils::fileName(p_path));
- }
- void FileUtils::copyFile(const QString &p_filePath,
- const QString &p_destPath,
- bool p_move)
- {
- if (PathUtils::areSamePaths(p_filePath, p_destPath)) {
- return;
- }
- QDir dir;
- if (!dir.mkpath(PathUtils::parentDirPath(p_destPath))) {
- Exception::throwOne(Exception::Type::FailToCreateDir,
- QString("failed to create directory: %1").arg(PathUtils::parentDirPath(p_destPath)));
- }
- bool failed = false;
- if (p_move) {
- QFile file(p_filePath);
- if (!file.rename(p_destPath)) {
- failed = true;
- }
- } else {
- if (!QFile::copy(p_filePath, p_destPath)) {
- failed = true;
- }
- }
- if (failed) {
- Exception::throwOne(Exception::Type::FailToCopyFile,
- QString("failed to copy file: %1 %2").arg(p_filePath, p_destPath));
- }
- }
- void FileUtils::copyDir(const QString &p_dirPath,
- const QString &p_destPath,
- bool p_move)
- {
- if (PathUtils::areSamePaths(p_dirPath, p_destPath)) {
- return;
- }
- if (QFileInfo::exists(p_destPath)) {
- Exception::throwOne(Exception::Type::FailToCopyDir,
- QString("target directory %1 already exists").arg(p_destPath));
- }
- // QDir.rename() could not move directory across dirves.
- // Create target directory.
- QDir destDir(p_destPath);
- if (!destDir.mkpath(p_destPath)) {
- Exception::throwOne(Exception::Type::FailToCreateDir,
- QString("failed to create directory: %1").arg(p_destPath));
- }
- // Copy directory contents recursively.
- QDir srcDir(p_dirPath);
- auto nodes = srcDir.entryInfoList(QDir::Dirs
- | QDir::Files
- | QDir::Hidden
- | QDir::NoSymLinks
- | QDir::NoDotAndDotDot);
- for (const auto &node : nodes) {
- auto name = node.fileName();
- if (node.isDir()) {
- copyDir(srcDir.filePath(name), destDir.filePath(name), p_move);
- } else {
- Q_ASSERT(node.isFile());
- copyFile(srcDir.filePath(name), destDir.filePath(name), p_move);
- }
- }
- if (p_move) {
- if (!destDir.rmdir(p_dirPath)) {
- Exception::throwOne(Exception::Type::FailToRemoveDir,
- QString("failed to remove source directory after move: %1").arg(p_dirPath));
- }
- }
- }
- QString FileUtils::renameIfExistsCaseInsensitive(const QString &p_path)
- {
- QFileInfo fi(p_path);
- auto dirPath = fi.absolutePath();
- auto baseName = fi.completeBaseName();
- auto suffix = fi.suffix();
- auto name = fi.fileName();
- int idx = 1;
- while (childExistsCaseInsensitive(dirPath, name)) {
- name = QString("%1_%2").arg(baseName, QString::number(idx));
- if (!suffix.isEmpty()) {
- name += QStringLiteral(".") + suffix;
- }
- ++idx;
- }
- return PathUtils::concatenateFilePath(dirPath, name);
- }
- void FileUtils::removeFile(const QString &p_filePath)
- {
- Q_ASSERT(!QFileInfo::exists(p_filePath) || QFileInfo(p_filePath).isFile());
- QFile file(p_filePath);
- if (!file.remove()) {
- Exception::throwOne(Exception::Type::FailToRemoveFile,
- QString("failed to remove file: %1").arg(p_filePath));
- }
- }
- bool FileUtils::removeDirIfEmpty(const QString &p_dirPath)
- {
- QDir dir(p_dirPath);
- if (!dir.isEmpty()) {
- return false;
- }
- if (!dir.rmdir(p_dirPath)) {
- Exception::throwOne(Exception::Type::FailToRemoveFile,
- QString("failed to remove directory: %1").arg(p_dirPath));
- return false;
- }
- return true;
- }
- void FileUtils::removeDir(const QString &p_dirPath)
- {
- QDir dir(p_dirPath);
- if (!dir.removeRecursively()) {
- Exception::throwOne(Exception::Type::FailToRemoveFile,
- QString("failed to remove directory recursively: %1").arg(p_dirPath));
- }
- }
- bool FileUtils::isPlatformNameCaseSensitive()
- {
- #if defined(Q_OS_WIN)
- return false;
- #else
- return true;
- #endif
- }
- bool FileUtils::isText(const QString &p_filePath)
- {
- QMimeDatabase mimeDatabase;
- auto mimeType = mimeDatabase.mimeTypeForFile(p_filePath);
- const auto name = mimeType.name();
- if (name.startsWith(QStringLiteral("text/")) || name == QStringLiteral("application/x-zerosize")) {
- return true;
- }
- return mimeType.inherits(QStringLiteral("text/plain"));
- }
- bool FileUtils::isImage(const QString &p_filePath)
- {
- QMimeDatabase mimeDatabase;
- auto mimeType = mimeDatabase.mimeTypeForFile(p_filePath);
- if (mimeType.name().startsWith(QStringLiteral("image/"))) {
- return true;
- }
- return false;
- }
- QImage FileUtils::imageFromFile(const QString &p_filePath)
- {
- QImage img(p_filePath);
- if (!img.isNull()) {
- return img;
- }
- // @p_filePath may has a wrong suffix which indicates a wrong image format.
- img.loadFromData(readFile(p_filePath));
- return img;
- }
- QPixmap FileUtils::pixmapFromFile(const QString &p_filePath)
- {
- QPixmap pixmap;
- pixmap.loadFromData(readFile(p_filePath));
- return pixmap;
- }
- QString FileUtils::generateUniqueFileName(const QString &p_folderPath,
- const QString &p_hints,
- const QString &p_suffix)
- {
- auto fileName = generateRandomFileName(p_hints, p_suffix);
- int suffixIdx = fileName.lastIndexOf(QLatin1Char('.'));
- auto baseName = suffixIdx == -1 ? fileName : fileName.left(suffixIdx);
- auto suffix = suffixIdx == -1 ? QStringLiteral("") : fileName.mid(suffixIdx);
- int index = 1;
- while (childExistsCaseInsensitive(p_folderPath, fileName)) {
- fileName = QString("%1_%2%3").arg(baseName, QString::number(index++), suffix);
- }
- return fileName;
- }
- QString FileUtils::generateRandomFileName(const QString &p_hints, const QString &p_suffix)
- {
- Q_UNUSED(p_hints);
- // Do not use toSecsSinceEpoch() here since we want a short name.
- const QString timeStamp(QDateTime::currentDateTime().toString(QStringLiteral("sszzzmmHHyyMMdd")));
- const QString baseName(QString::number(timeStamp.toLongLong() + qrand()));
- QString suffix;
- if (!p_suffix.isEmpty()) {
- suffix = QLatin1Char('.') + p_suffix.toLower();
- }
- return baseName + suffix;
- }
- QTemporaryFile *FileUtils::createTemporaryFile(const QString &p_suffix)
- {
- QString xx = p_suffix.isEmpty() ? QStringLiteral("XXXXXX") : QStringLiteral("XXXXXX.");
- return new QTemporaryFile(QDir::tempPath() + QDir::separator() + xx + p_suffix);
- }
- QString FileUtils::generateFileNameWithSequence(const QString &p_folderPath,
- const QString &p_baseName,
- const QString &p_suffix)
- {
- auto fileName = p_suffix.isEmpty() ? p_baseName : p_baseName + QLatin1Char('.') + p_suffix;
- auto suffix = p_suffix.isEmpty() ? QString() : QStringLiteral(".") + p_suffix;
- int index = 1;
- while (childExistsCaseInsensitive(p_folderPath, fileName)) {
- fileName = QString("%1_%2%3").arg(p_baseName, QString::number(index++), suffix);
- }
- return fileName;
- }
- void FileUtils::removeEmptyDir(const QString &p_dirPath)
- {
- QDir dir(p_dirPath);
- if (dir.isEmpty()) {
- return;
- }
- auto childDirs = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
- for (const auto &child : childDirs) {
- const auto childPath = child.absoluteFilePath();
- removeEmptyDir(childPath);
- removeDirIfEmpty(childPath);
- }
- }
- QStringList FileUtils::entryListRecursively(const QString &p_dirPath,
- const QStringList &p_nameFilters,
- QDir::Filters p_filters)
- {
- QStringList entries;
- QDir dir(p_dirPath);
- if (!dir.exists()) {
- return entries;
- }
- const auto curEntries = dir.entryList(p_nameFilters, p_filters | QDir::NoDotAndDotDot);
- for (const auto &e : curEntries) {
- entries.append(PathUtils::concatenateFilePath(p_dirPath, e));
- }
- const auto subdirs = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
- for (const auto &subdir : subdirs) {
- const auto dirPath = PathUtils::concatenateFilePath(p_dirPath, subdir);
- entries.append(entryListRecursively(dirPath, p_nameFilters, p_filters));
- }
- return entries;
- }
|