You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题排查与修复

核心问题分析

  1. 未跳过非文件条目:fs::directory_iterator会遍历目录下所有内容(包括文件夹、快捷方式),程序尝试对文件夹执行文件操作,触发异常。
  2. 扩展名获取逻辑冗余且危险:通过打开文件判断扩展名完全没必要,且打开文件夹、无权限文件时会导致错误,甚至耗尽文件句柄。
  3. 无异常捕获机制:文件系统操作、文件流操作可能抛出std::system_error,未捕获会直接导致程序崩溃。
  4. 路径拼接不规范:手动拼接字符串容易出现格式错误,且无法跨平台适配。

修复后的代码

修复后的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:35:25