C++中从/proc目录复制文件的最优安全方法(std::filesystem::copy_file失效)
解决C++中复制/proc/self/mountinfo的问题
/proc下的文件是内核提供的虚拟文件,并非磁盘上的常规实体文件,std::filesystem::copy_file()依赖常规文件的元数据和I/O逻辑,因此无法直接处理这类虚拟文件。除了手动打开文件读取再写入的方式,还有两种简单安全的实现方案:
方案一:C标准库流式分块拷贝(跨平台通用)
这种方式本质仍是文件读写,但通过分块读取避免一次性加载全部内容到内存,更安全高效,代码也简洁易维护:
#include <cstdio> #include <stdexcept> void copy_proc_file(const char* src_path, const char* dest_path) { FILE* src = std::fopen(src_path, "r"); if (!src) { throw std::runtime_error("无法打开源文件"); } FILE* dest = std::fopen(dest_path, "w"); if (!dest) { std::fclose(src); throw std::runtime_error("无法打开目标文件"); } char buffer[4096]; size_t bytes_read; while ((bytes_read = std::fread(buffer, 1, sizeof(buffer), src)) > 0) { if (std::fwrite(buffer, 1, bytes_read, dest) != bytes_read) { std::fclose(src); std::fclose(dest); throw std::runtime_error("写入目标文件失败"); } } if (std::ferror(src)) { std::fclose(src); std::fclose(dest); throw std::runtime_error("读取源文件失败"); } std::fclose(src); std::fclose(dest); } // 使用示例 int main() { try { copy_proc_file("/proc/self/mountinfo", "/tmp/mountinfo_copy"); } catch (const std::exception& e) { // 这里可以添加错误日志或用户提示 return 1; } return 0; }
方案二:Linux系统调用copy_file_range(性能最优)
如果程序仅需在Linux环境运行,copy_file_range是内核提供的高效拷贝系统调用,能直接在内核空间完成数据传输,避免用户态与内核态的多次切换,性能更优,且支持虚拟文件的拷贝:
#include <fcntl.h> #include <unistd.h> #include <stdexcept> #include <cstdint> void copy_proc_file(const char* src_path, const char* dest_path) { int src_fd = open(src_path, O_RDONLY); if (src_fd == -1) { throw std::runtime_error("无法打开源文件"); } int dest_fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (dest_fd == -1) { close(src_fd); throw std::runtime_error("无法打开目标文件"); } off64_t src_offset = 0; off64_t dest_offset = 0; ssize_t bytes_copied; while ((bytes_copied = copy_file_range(src_fd, &src_offset, dest_fd, &dest_offset, 4096, 0)) > 0) { // 循环直到拷贝完成 } if (bytes_copied == -1) { close(src_fd); close(dest_fd); throw std::runtime_error("文件拷贝失败"); } close(src_fd); close(dest_fd); } // 使用示例 int main() { try { copy_proc_file("/proc/self/mountinfo", "/tmp/mountinfo_copy"); } catch (const std::exception& e) { // 这里可以添加错误日志或用户提示 return 1; } return 0; }
关键注意事项
- 虚拟文件的大小通常显示为0,但实际可读取到有效内容,因此不能依赖文件大小判断读取终点,必须循环读取直到EOF。
- 两种方案都包含完整的错误处理,确保文件描述符/指针被正确关闭,避免资源泄漏。
内容的提问来源于stack exchange,提问作者bun9
相关产品推荐
相关产品推荐

