windows 文件夹删除 遍历等操作

在 windows 上面如何进行一些文件夹的操作,比如删除文件夹 、判断是否是文件夹、获取文件夹大小等。

使用 win 32 api 实现文件夹操作

查询 win32 api 你会发现没有直接的函数可以使用,win 32 api 只提供了DeleteFile(删除文件)、RemoveDirectory (删除空文件夹)、GetFileSizeEx(获取文件大小)等操作文件相关 api,但是我们可以通过遍历文件夹的方式,对文件夹进行操作。

//  判断是否是文件夹
bool IsDirectory(std::wstring& dir) {
  DWORD dw_attribute = ::GetFileAttributes(dir.c_str());
  if ((INVALID_FILE_ATTRIBUTES != dw_attribute) &&
    (FILE_ATTRIBUTE_DIRECTORY & dw_attribute)) {
    return true;
  }
  return false;
}

// 获取文件夹大小
uint64_t GetFolderSize(const std::wstring& dir) {
  uint64_t folder_size = 0;
  std::wstring dir_full_path = dir;
  if (dir_full_path.back() != '\\') {
    dir_full_path += L"\\";
  }

  std::vector<std::wstring> vec_dir;
  vec_dir.reserve(1000);
  vec_dir.push_back(dir_full_path);
  size_t i = 0;
  size_t size = vec_dir.size();
  while (i < size) {
    std::wstring str_dir = vec_dir[i];
    WIN32_FIND_DATAW find_file_data;
    memset(&find_file_data, 0, sizeof(find_file_data));
    HANDLE hfind = ::FindFirstFile((str_dir + L"*.*").c_str(), &find_file_data);
    if (hfind != INVALID_HANDLE_VALUE) {
      BOOL bFind = TRUE;
      while (bFind) {
        std::wstring strFile = str_dir + find_file_data.cFileName;
        if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
          if (StrCmp(find_file_data.cFileName, _T("..")) != 0 &&
            StrCmp(find_file_data.cFileName, _T(".")) != 0) {
            vec_dir.push_back(strFile + _T("\\"));
          }
        } else {
          LARGE_INTEGER file_size = { 0 };
          file_size.LowPart = find_file_data.nFileSizeLow;
          file_size.HighPart = find_file_data.nFileSizeHigh;
          folder_size += file_size.QuadPart;
        }
        bFind = ::FindNextFile(hfind, &find_file_data);
      }
      FindClose(hfind);
    }
    i++;
    size = vec_dir.size();
  }
  return folder_size;
}

// 删除文件夹
bool DeleteDirectory(const std::wstring& dir) {
  if (dir.empty()) {
    log_fault << "dir is empty.";
    return false;
  }
  bool ret = true;
  std::wstring dir_full_path = dir;
  if (dir_full_path.back() != '\\') {
    dir_full_path += L"\\";
  }

  std::vector<std::wstring> vec_dir;
  vec_dir.reserve(100);
  vec_dir.push_back(dir_full_path);
  int i = 0;
  int size = vec_dir.size();
  while (i < size) {
    std::wstring str_dir = vec_dir[i];
    WIN32_FIND_DATAW find_file_data;
    memset(&find_file_data, 0, sizeof(find_file_data));
    HANDLE hfind = ::FindFirstFile((str_dir + L"*.*").c_str(), &find_file_data);
    if (hfind != INVALID_HANDLE_VALUE) {
      bool find = true;
      while (find) {
        std::wstring str_file = str_dir + find_file_data.cFileName;
        if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
          if (StrCmp(find_file_data.cFileName, _T("..")) != 0 &&
            StrCmp(find_file_data.cFileName, _T(".")) != 0) {
            vec_dir.push_back(str_file + _T("\\"));
          }
        } else {
          if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
            DWORD dwFileAttributes = find_file_data.dwFileAttributes & (~FILE_ATTRIBUTE_READONLY);
            SetFileAttributes(str_file.c_str(), dwFileAttributes);
          }

          if (!::DeleteFile(str_file.c_str())) {
            ret = false;
            break;
          }
        }
        find = ::FindNextFile(hfind, &find_file_data);
      }
      FindClose(hfind);
    }
    i++;
    size = vec_dir.size();
  }
  if (ret && !vec_dir.empty()) {
    for (i = vec_dir.size() - 1; i >= 0; i--) {
      ret = ::RemoveDirectory(vec_dir[i].c_str());
      if (!ret) {
        return false;
      }
    }
  }
  return true;
}

使用QT 的 QDir QFile 等类实现该功能

使用 QDir QFile 等类的实现方式Qt 官方文档有很多介绍,这里就不再赘述了。读者可以自行查看。

使用 C++ 17 的 filesystem 系统

C++ 17 新增了 filesystem 文件系统,提供了一些很方便使用的功能:

  1. 路径操作 (std::filesystem::path): 用于处理文件和目录路径的类。
    操作如拼接、解析、检查路径格式等。

  2. 文件和目录的创建、删除和查询:
    创建和删除文件夹 (create_directory, remove, remove_all 等)。
    检查文件或文件夹的存在 (exists) 和状态 (is_directory, is_regular_file 等)。
    文件大小和文件系统空间信息:

  3. 查询文件大小 (file_size),以及文件系统的空闲空间和容量 (space 等)。

  4. 文件和目录的复制、移动和重命名:
    如 copy, copy_file, move, rename 等函数。

  5. 目录遍历:
    使用 std::filesystem::directory_iterator 或 std::filesystem::recursive_directory_iterator 遍历目录。

  6. 文件属性和权限:
    获取和设置文件权限 (permissions),读取最后一次修改时间 (last_write_time) 等。

看起来也是非常方便了,可以满足我们对文件夹的常规操作要求了。

但是,这里要划重点,C++ 17 的 filesysetem 与 Qt 或者 win 32 api 在使用上有什么异同?

三种方式之间的区别

使用方式上的区别主要在于异常处理和错误反馈方面,Qt 文件处理 api 和 win 32 api 都是通过错误误代码和返回值告诉调用者错误信息,而 C++ 标准库则提供了错误码和异常处理机制。也就是说使用 win32 和 Qt 的 api 是不需要处理异常的,但是如果你是在使用 C++ 17 filesystem,必须要关注异常处理,否侧如果有未处理的异常,会引起 app crash。

C++ 17 filesystem 同时提供了错误码和异常两种错误信息,使用的时候一定要查看清楚该 api 是否会抛出异常。

一般有错误码返回的是不会抛出异常的,比如判断文件是否存在的 exist 函数,明确表示不会抛出异常
在这里插入图片描述

需要注意的是,同时有一个重载的函数,会调用上面的函数并抛出异常:
在这里插入图片描述
C++ 的 try cache 异常捕获机制貌似平日开发使用的比较少了,所以,使用 filesystem 的时候一定要注意了,如果你使用的 filesystem 有异常抛出但是忘记了捕获就惨了…

如果你不想处理异常,想要使用 Qt 或者 win32 api 的方式处理异常,那你可以选择使用返回错误码的api(有些可以返回错误码,但是并没有标明不会抛出异常,这种也需要捕获异常),而不是抛出异常的 api。
在这里插入图片描述

但是有些情况下,比如遍历文件夹或者递归遍历文件夹,必须捕获异常,因为迭代器自增的时候,有可能会抛出异常:
在这里插入图片描述
可以看到构造的时候有带错误码的构造函数,但是并没有标明不会抛出异常。而且截图中第一个构造函数明确会抛出异常。

在这里插入图片描述
迭代器自增的方法明确会抛出异常。

递归遍历的迭代器也是一样的:
在这里插入图片描述
在这里插入图片描述

所以,使用 C++ 17 filesystem 的时候,一定要关注它的异常处理,这是跟 QT 或者 win32 api 设计以及使用上的最大的不同!!!。

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值