C++文件拷贝程序抛出std::system_error异常的排查与修复
问题描述
编写了一段C++程序,用于从指定目录C:\Users\niko\Desktop获取所有格式为.txt、.jpg、.jpeg、.png、.doc、.docx的文件,并将其拷贝至U盘路径E:\Targets。编写过程无报错,但编译运行后,程序仅读取4-5个文件即抛出未处理异常:
Unhandled exception at 0x00007FFB27A2CB69 in MyTestCodes.exe: Microsoft C++ exception: std::system_error at memory location 0x000000C8444FE940。
当将目标路径改为桌面单个文件路径时,程序可正常运行。请求帮助排查并修复该错误。
原程序代码
#include "MyTestCodes.h" using namespace std; int main() { string getPath = "C:\\Users\\niko\\Desktop"; string format,name,path; fs::create_directory("E:\\Targets"); for (const auto& targetPath : fs::directory_iterator(getPath)) { path = targetPath.path().generic_string(); name = getName(path); format = ext(path); cout << "path : " << path << endl; cout << "name : " << name << endl; cout << "Format : " << format << endl; if (format == ".txt" ) { cout << "TEXT!"; string targetText; ifstream targetFile(path); bool fileAvailable = targetFile.is_open(); if (fileAvailable) { getline(targetFile, targetText); ofstream textFile("E:\\Targets\\" + name + format); bool fileWorked = textFile.is_open(); if (fileWorked) { textFile << targetText; textFile.close(); } } } else if(format == ".jpg" || format == ".jpeg" || format == ".png" || format == ".doc" || format == ".docx") { ifstream targetFile(path, ios::binary); bool fileAvailable = targetFile.is_open(); ofstream file("E:\\Targets\\" + name + format, ios::binary); if (fileAvailable) { file << targetFile.rdbuf(); } } } return 0; }
原头文件代码(MyTestCodes.h)
#pragma once //Libraries Used #include <iostream> //Input/Output Stream For Console #include <string> //For String #include <fstream> //File Stream #include <vector> //Changable Index Structure #include <Windows.h>//For System Commands #include <algorithm>//Easy Sorting For Arrays/Vectors ... #include <iomanip> //For Outputting With Given Precision #include <cmath> //Easy Math Functions #include <stdio.h> //Standard Input/Output For Given Types #include <conio.h> //For getting Key Presses #include <ctime> //For getting real time #include <filesystem> #include <mmsystem.h> #include <Mmsystem.h> #include <mciapi.h> #pragma comment(lib, "Winmm.lib") using namespace std; // Standard namespace namespace fs = filesystem; //For Getting File's Format On Given Path string ext(string path) { ifstream CFile(path); //Checking/Reading File bool opened = CFile.is_open(); //bool For Checking if (opened) // If Available { string ext = ""; //Set Extension To Nothing size_t size = path.size(); //Get Size Of Path size_t lastPos = size; //Get LastPos(Will Be Used Later) char letter; //Letter For Given Position bool ThereIsDot = false; //Check If There Is Format for (size_t i = 0; i < size; i++) //Loop To Extract Chars { letter = path[i]; // Get Char On Given Index if (letter == '.') // If Symbol Is Dot { lastPos = i; // Starting Index Of Format ThereIsDot = true; // There Is Format } } if (ThereIsDot) //If Format Is Given { for (size_t i = lastPos; i < size; i++) //Loop For Format Chars { letter = path[i]; //Get Char On Given Index ext += letter; //Get Format } return ext; //Give Extension Of File } else { return "ERROR"; //Give ERROR If There Is No Extension } } else { return "ERROR"; //Give ERROR If File Not Opened } } string getName(string target) { size_t size = target.size(); char symbol; size_t lastPos = size; string result; for (size_t i = 0; i < size; i++) { symbol = target[i]; if (symbol == '/' || symbol == '\\') { lastPos = i; } } for (size_t i = lastPos + 1; i < size; i++) { symbol = target[i]; if (symbol == '.') { break; } result += symbol; } return result; }
终端输出
path : C:/Users/niko/Desktop/ALPLogo.lnk name : ALPLogo Format : .lnk path : C:/Users/niko/Desktop/Arduino IDE.lnk name : Arduino IDE Format : .lnk path : C:/Users/niko/Desktop/Data name : Data Format : ERROR path : C:/Users/niko/Desktop/desktop.ini name : desktop Format : .ini path : C:/Users/niko/Desktop/Dev-C++.lnk name : Dev-C++ Format : .lnk path : C:/Users/niko/Desktop/Discord.lnk name : Discord Format : .lnk
问题排查与修复
核心问题分析
- 未跳过非文件条目:
fs::directory_iterator会遍历目录下所有内容(包括文件夹、快捷方式),程序尝试对文件夹执行文件操作,触发异常。 - 扩展名获取逻辑冗余且危险:通过打开文件判断扩展名完全没必要,且打开文件夹、无权限文件时会导致错误,甚至耗尽文件句柄。
- 无异常捕获机制:文件系统操作、文件流操作可能抛出
std::system_error,未捕获会直接导致程序崩溃。 - 路径拼接不规范:手动拼接字符串容易出现格式错误,且无法跨平台适配。
修复后的代码
修复后的MyTestCodes.h
#pragma once #include <iostream> #include <string> #include <fstream> #include <vector> #include <Windows.h> #include <algorithm> #include <iomanip> #include <cmath> #include <stdio.h> #include <conio.h> #include <ctime> #include <filesystem> #include <mmsystem.h> #include <mciapi.h> #pragma comment(lib, "Winmm.lib") using namespace std; namespace fs = filesystem; // 直接从路径解析扩展名,无需打开文件 string ext(const string& path) { fs::path file_path(path); return file_path.has_extension() ? file_path.extension().string() : "ERROR"; } // 直接从路径解析文件名(不含扩展名) string getName(const string& target) { fs::path file_path(target); return file_path.has_filename() ? file_path.stem().string() : ""; }
修复后的main函数
#include "MyTestCodes.h" using namespace std; int main() { try { fs::path sourceDir = "C:\\Users\\niko\\Desktop"; fs::path targetDir = "E:\\Targets"; // 递归创建目录,已存在时不会报错 fs::create_directories(targetDir); // 遍历目录,仅处理普通文件 for (const auto& entry : fs::directory_iterator(sourceDir)) { if (!entry.is_regular_file()) { continue; // 跳过文件夹、快捷方式等非文件 } fs::path filePath = entry.path(); string pathStr = filePath.generic_string(); string name = getName(pathStr); string format = ext(pathStr); cout << "path : " << pathStr << endl; cout << "name : " << name << endl; cout << "Format : " << format << endl; if (format == ".txt") { cout << "TEXT!" << endl; ifstream targetFile(filePath); if (targetFile.is_open()) { string targetText; getline(targetFile, targetText); fs::path outputPath = targetDir / (name + format); ofstream textFile(outputPath); if (textFile.is_open()) { textFile << targetText; } targetFile.close(); } } else if (format == ".jpg" || format == ".jpeg" || format == ".png" || format == ".doc" || format == ".docx") { ifstream targetFile(filePath, ios::binary); if (targetFile.is_open()) { fs::path outputPath = targetDir / (name + format); ofstream outputFile(outputPath, ios::binary); if (outputFile.is_open()) { outputFile << targetFile.rdbuf(); } targetFile.close(); } } } } catch (const std::exception& e) { cerr << "错误信息: " << e.what() << endl; return 1; } return 0; }
修复说明
- 过滤非文件条目:通过
entry.is_regular_file()跳过文件夹、快捷方式等,避免无效操作。 - 简化路径解析:利用
std::filesystem::path的内置方法获取扩展名和文件名,无需手动解析字符串,更可靠高效。 - 添加异常捕获:用
try-catch捕获所有标准异常,输出错误信息,避免程序直接崩溃。 - 规范路径拼接:使用
fs::path的/运算符拼接路径,自动适配系统路径分隔符,避免手动拼接错误。
内容的提问来源于stack exchange,提问作者Merd Ceferzade
相关产品推荐
相关产品推荐

