XML通过HTTP POST 请求发送到指定的 API 地址,进行数据回传代码改进想法

最原始的版本:代码结构说明
这段代码的主要功能是:

从指定文件夹中读取所有 XML 文件

将每个 XML 文件的内容通过 HTTP POST 请求发送到指定的 API 地址。

处理服务器的响应,并记录每个文件的处理结果。

代码功能详解

  1. 文件夹路径和 API 配置

    • xmlFolderPath:指定存放 XML 文件的文件夹路径。

    • apiUrl:华为服务器的 API 地址。

    • appId 和 appKey:用于身份验证的 AppId 和 AppKey。

    • topic 和 tag:消息的主题和标签。

  2. 读取文件夹中的 XML 文件

    • 使用 Directory.GetFiles 方法获取文件夹中所有 .xml 文件。

    • 如果文件夹中没有文件,输出提示并退出程序。

  3. 遍历并处理每个 XML 文件

    • 使用 foreach 循环遍历每个文件。

    • 调用 ReadXmlFile 方法读取文件内容。

    • 调用 SendHttpRequest 方法将文件内容发送到服务器。

    • 捕获并处理可能发生的异常(如文件格式错误、读取失败、HTTP 请求失败等)。

  4. 读取 XML 文件内容

    • 使用 StreamReader 读取文件内容,并指定文件编码为 GB2312

    • 如果文件不存在,抛出 FileNotFoundException 异常。

  5. 发送 HTTP 请求

    • 使用 HttpWebRequest 创建 HTTP POST 请求。

    • 设置请求头(AppId、AppKey、Topic、Tag)。

    • 将 XML 内容写入请求体。

    • 获取服务器响应并返回响应内容。

  6. 异常处理

    • 对文件读取、XML 解析、HTTP 请求等操作进行异常捕获,确保程序健壮性。


代码运行流程

  1. 程序启动后,检查指定文件夹中是否存在 XML 文件。

  2. 如果存在文件,逐个读取文件内容并发送到服务器。

  3. 每次发送后,输出服务器的响应内容。

  4. 如果发生错误,输出错误信息并继续处理下一个文件。


注意事项

  1. 文件编码

    • 代码中假设 XML 文件的编码是 GB2312,如果文件编码不同,需要调整 StreamReader 的编码参数。

  2. HTTP 请求超时

    • 如果服务器响应较慢,可能需要设置 HttpWebRequest.Timeout 属性,避免请求长时间挂起。

  3. 异常处理

    • 代码中对常见异常进行了捕获,但可以根据实际需求进一步细化异常处理逻辑。


如果有其他问题,欢迎继续讨论!

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;

namespace EMS数据回传
{
    class Program
    {
        static void Main(string[] args)
        {
            // XML 文件夹路径
            string xmlFolderPath = @"Z:\toMesXml";

            // 服务器 API 地址
            string apiUrl = "服务器 API 地址";

            // 你的 AppId
            string appId = "你的 AppId";

            // 你的 AppKey
            string appKey = "你的 AppKey";

            // Topic 名称
            string topic = "Topic 名称";

            // 消息 Tag
            string tag = "消息 Tag";

            try
            {
                // 获取文件夹中的所有 XML 文件
                string[] xmlFiles = Directory.GetFiles(xmlFolderPath, "*.xml");

                // 如果文件夹中没有 XML 文件,输出提示并退出
                if (xmlFiles.Length == 0)
                {
                    Console.WriteLine("文件夹中没有 XML 文件。");
                    return;
                }

                // 遍历每个 XML 文件并发送
                foreach (string xmlFile in xmlFiles)
                {
                    try
                    {
                        // 输出当前正在处理的文件
                        Console.WriteLine(string.Format("正在处理文件: {0}", xmlFile));

                        // 1. 读取 XML 文件内容
                        string xmlContent = ReadXmlFile(xmlFile);

                        // 2. 发送 HTTP 请求
                        string response = SendHttpRequest(apiUrl, appId, appKey, topic, tag, xmlContent);

                        // 3. 处理响应,输出发送成功的信息
                        Console.WriteLine(string.Format("文件 {0} 发送成功,服务器响应: {1}", xmlFile, response));
                    }
                    catch (XmlException ex)
                    {
                        // 捕获 XML 格式错误
                        Console.WriteLine(string.Format("文件 {0} 格式错误: {1}", xmlFile, ex.Message));
                    }
                    catch (IOException ex)
                    {
                        // 捕获文件读取失败错误
                        Console.WriteLine(string.Format("文件 {0} 读取失败: {1}", xmlFile, ex.Message));
                    }
                    catch (WebException ex)
                    {
                        // 捕获 HTTP 请求失败错误
                        Console.WriteLine(string.Format("文件 {0} 发送失败,HTTP 错误: {1}", xmlFile, ex.Message));
                    }
                    catch (Exception ex)
                    {
                        // 捕获其他未知错误
                        Console.WriteLine(string.Format("文件 {0} 发生未知错误: {1}", xmlFile, ex.Message));
                    }
                }
            }
            catch (Exception ex)
            {
                // 捕获全局错误
                Console.WriteLine("发生错误: " + ex.Message);
            }
        }

        // 读取 XML 文件内容
        static string ReadXmlFile(string filePath)
        {
            // 检查文件是否存在,如果不存在则抛出异常
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("XML 文件未找到: " + filePath);
            }

            // 使用 StreamReader 指定编码读取文件
            using (StreamReader reader = new StreamReader(filePath, Encoding.GetEncoding("GB2312"))) // 根据文件编码调整
            {
                // 读取文件的全部内容并返回
                string xmlContent = reader.ReadToEnd();
                return xmlContent;
            }
        }

        // 发送 HTTP 请求
        static string SendHttpRequest(string url, string appId, string appKey, string topic, string tag, string xmlContent)
        {
            // 创建 HTTP 请求
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

            // 设置请求方法为 POST
            request.Method = "POST";

            // 设置请求内容类型为 XML
            request.ContentType = "application/xml";

            // 添加请求头
            request.Headers.Add("X-HW-ID", appId);       // AppId
            request.Headers.Add("X-HW-APPKEY", appKey);  // AppKey
            request.Headers.Add("MsgTopic", topic);      // Topic
            request.Headers.Add("MsgTag", tag);          // Tag

            // 将 XML 内容转换为字节数组
            byte[] data = Encoding.UTF8.GetBytes(xmlContent);

            // 设置请求内容的长度
            request.ContentLength = data.Length;

            // 将 XML 内容写入请求体
            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(data, 0, data.Length);
            }

            // 获取服务器响应
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            using (Stream responseStream = response.GetResponseStream())
            using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8))
            {
                // 读取服务器响应的内容并返回
                return reader.ReadToEnd();
            }
        }
    }
}

第一版本代码改进,当然,我会在代码中对改动的地方进行标记。以下是改进后的代码,并在改动处添加了注释以突出显示:

### 改动标记说明:
1. **配置 `HttpClient`**:
   - **新增方法**: `ConfigureHttpClient` 方法用于配置 `HttpClient`。
   
2. **日志输出**:
   - **新增日志输出**: 在关键步骤增加了详细的日志输出,如开始处理时间、发现的文件数量、处理进度、成功上传的数量和结束时间等。

3. **错误处理**:
   - **新增错误日志记录**: 在捕获异常时调用 `LogError` 方法记录详细的错误信息。

4. **重试机制**:
   - **新增方法**: `SendHttpRequestWithRetryAsync` 方法实现了带有重试机制的 HTTP 请求发送。

5. **异步处理**:
   - **异步方法调用**: 在多个地方使用 `await` 关键字进行异步操作,如 `SendHttpRequestWithRetryAsync` 和 `SendHttpRequestAsync`。

6. **资源管理**:
   - **确保资源释放**: 在 `finally` 块中调用 `httpClient.Dispose()` 确保资源得到释放。

7. **性能优化**:
   - **批量处理**: 使用 LINQ 进行批量处理,减少循环次数和方法调用开销。

这些改动显著提升了代码的性能、可靠性和可维护性。

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Linq;

namespace EMS数据回传
{
    class Program
    {
        // 创建一个静态的 HttpClient 实例以提高性能
        private static readonly HttpClient httpClient = new HttpClient();
        
        static async Task Main(string[] args)
        {
            // 注册编码提供程序,支持 GB2312
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            // 配置参数
            string baseFolderPath = @"Z:\彩盒CCD"; // 基础文件夹路径
            string apiUrl = ""; // 华为服务器 API 地址
            string appId = ""; // 你的 AppId
            string appKey = ""; // 你的 AppKey
            string topic = ""; // Topic 名称
            string tag = ""; // 消息 Tag
            string uploadedFilesLog = "uploaded_files.txt"; // 记录已上传文件的日志文件
            int maxRetries = 3; // 最大重试次数

            try
            {
                // 配置 HttpClient (新增方法调用)
                ConfigureHttpClient(apiUrl, appId, appKey, topic, tag); // 改动
                
                // 加载已上传的文件记录
                HashSet<string> uploadedFiles = LoadUploadedFiles(uploadedFilesLog);
                int totalProcessed = 0;
                int totalSuccess = 0;

                Console.WriteLine($"开始处理,时间: {DateTime.Now}"); // 新增日志输出
                
                // 遍历 1-19 线
                for (int lineNumber = 1; lineNumber <= 19; lineNumber++)
                {
                    string lineFolder = Path.Combine(baseFolderPath, $"{lineNumber}线");
                    string toMesXmlFolder = Path.Combine(lineFolder, "toMesXml");

                    // 检查 toMesXml 文件夹是否存在
                    if (!Directory.Exists(toMesXmlFolder))
                    {
                        Console.WriteLine($"文件夹 {toMesXmlFolder} 不存在,跳过处理。");
                        continue;
                    }

                    // 获取 toMesXml 文件夹中的所有 XML 文件
                    string[] xmlFiles = Directory.GetFiles(toMesXmlFolder, "*.xml");

                    if (xmlFiles.Length == 0)
                    {
                        Console.WriteLine($"文件夹 {toMesXmlFolder} 中没有 XML 文件。");
                        continue;
                    }

                    Console.WriteLine($"发现 {xmlFiles.Length} 个XML文件在 {lineNumber}线"); // 新增日志输出
                    
                    // 遍历每个 XML 文件并发送
                    foreach (string xmlFile in xmlFiles)
                    {
                        try
                        {
                            string fileName = Path.GetFileName(xmlFile);
                            totalProcessed++;

                            // 检查文件是否已经上传过
                            if (uploadedFiles.Contains(fileName))
                            {
                                Console.WriteLine($"文件 {fileName} 已经上传过,跳过处理。");
                                continue;
                            }

                            Console.WriteLine($"正在处理文件: {fileName}");

                            // 1. 读取 XML 文件内容
                            string xmlContent = ReadXmlFile(xmlFile);

                            // 2. 发送 HTTP 请求(带重试机制)
                            string response = await SendHttpRequestWithRetryAsync(xmlContent, maxRetries); // 异步方法调用

                            // 3. 处理响应
                            Console.WriteLine($"文件 {fileName} 发送成功,服务器响应: {response}");
                            totalSuccess++;

                            // 4. 记录已上传的文件名
                            uploadedFiles.Add(fileName);
                            File.AppendAllText(uploadedFilesLog, fileName + Environment.NewLine);
                        }
                        catch (Exception ex)
                        {
                            LogError($"文件 {xmlFile} 发生错误", ex); // 新增错误日志记录
                        }
                    }
                }
                
                Console.WriteLine($"处理完成,总共处理: {totalProcessed} 个文件,成功: {totalSuccess} 个,时间: {DateTime.Now}"); // 新增总结日志输出
            }
            catch (Exception ex)
            {
                LogError("程序执行过程中发生错误", ex); // 新增错误日志记录
            }
            finally
            {
                httpClient.Dispose(); // 确保资源释放
            }
        }

        // 配置 HttpClient (新增方法)
        static void ConfigureHttpClient(string apiUrl, string appId, string appKey, string topic, string tag)
        {
            httpClient.BaseAddress = new Uri(apiUrl);
            httpClient.DefaultRequestHeaders.Clear();
            httpClient.DefaultRequestHeaders.Add("X-HW-ID", appId);
            httpClient.DefaultRequestHeaders.Add("X-HW-APPKEY", appKey);
            httpClient.DefaultRequestHeaders.Add("MsgTopic", topic);
            httpClient.DefaultRequestHeaders.Add("MsgTag", tag);
        }

        // 读取 XML 文件内容 (保持不变)
        static string ReadXmlFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("XML 文件未找到: " + filePath);
            }

            // 使用 StreamReader 指定编码读取文件
            using (StreamReader reader = new StreamReader(filePath, Encoding.GetEncoding("GB2312"))) // 根据文件编码调整
            {
                string xmlContent = reader.ReadToEnd();
                return xmlContent;
            }
        }

        // 发送 HTTP 请求(带重试机制) (新增方法)
        static async Task<string> SendHttpRequestWithRetryAsync(string xmlContent, int maxRetries)
        {
            int retryCount = 0;
            Exception lastException = null;

            while (retryCount < maxRetries)
            {
                try
                {
                    return await SendHttpRequestAsync(xmlContent); // 异步方法调用
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    retryCount++;
                    
                    if (retryCount < maxRetries)
                    {
                        int delayMs = 1000 * retryCount; // 递增延迟
                        Console.WriteLine($"请求失败,{delayMs/1000}秒后进行第{retryCount}次重试...");
                        await Task.Delay(delayMs); // 异步延迟
                    }
                }
            }

            throw new Exception($"在{maxRetries}次尝试后仍然失败", lastException);
        }

        // 发送 HTTP 请求(异步) (新增方法)
        static async Task<string> SendHttpRequestAsync(string xmlContent)
        {
            // 准备请求内容
            var content = new StringContent(xmlContent, Encoding.UTF8, "application/xml");
            
            // 发送请求
            var response = await httpClient.PostAsync("", content); // 异步请求
            
            // 确保请求成功
            response.EnsureSuccessStatusCode();
            
            // 读取响应
            return await response.Content.ReadAsStringAsync(); // 异步读取响应
        }

        // 加载已上传的文件记录 (优化)
        static HashSet<string> LoadUploadedFiles(string logFilePath)
        {
            HashSet<string> uploadedFiles = new HashSet<string>();

            // 如果日志文件存在,读取已上传的文件名
            if (File.Exists(logFilePath))
            {
                try
                {
                    string[] lines = File.ReadAllLines(logFilePath);
                    uploadedFiles = new HashSet<string>(lines.Select(line => line.Trim())); // 使用 LINQ 进行批量处理
                    Console.WriteLine($"已加载 {uploadedFiles.Count} 个已上传文件记录"); // 新增日志输出
                }
                catch (Exception ex)
                {
                    LogError("读取已上传文件记录时出错", ex); // 新增错误日志记录
                }
            }
            else
            {
                Console.WriteLine($"上传记录文件 {logFilePath} 不存在,将创建新文件"); // 新增日志输出
            }

            return uploadedFiles;
        }

        // 记录错误信息 (新增方法)
        static void LogError(string message, Exception ex)
        {
            Console.WriteLine($"错误: {message}");
            Console.WriteLine($"异常信息: {ex.Message}");
            Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
            
            // 记录到错误日志文件
            string errorLog = $"error_log_{DateTime.Now:yyyyMMdd}.txt";
            string errorMessage = $"[{DateTime.Now}] {message}\r\n{ex.Message}\r\n{ex.StackTrace}\r\n\r\n";
            File.AppendAllText(errorLog, errorMessage);
        }
    }
}



转写成C++代码

关键点说明:

  1. HTTP 请求:使用 libcurl 库发送 POST 请求。
  2. 文件操作:使用 C++17 的 <filesystem> 库处理文件和目录。
  3. 编码支持:如果需要支持 GB2312 编码,可以使用 iconv 或其他第三方库。
  4. 日志记录:通过文件流记录已上传的文件名。

如何运行:

  1. 安装 libcurl 和 filesystem 支持的编译器(如 GCC 或 MSVC)。
  2. 将代码保存为 .cpp 文件,并编译运行。
  3. 确保配置正确的路径和 API 参数。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_set>
#include <filesystem>
#include <chrono>
#include <thread>
#include <curl/curl.h>

namespace fs = std::filesystem;

// 配置参数
const std::string baseFolderPath = "Z:/彩盒CCD"; // 基础文件夹路径
const std::string apiUrl = "https://apigw-cn-south.huawei.com/api/mqs/message"; // 华为服务器 API 地址
const std::string appId = "huawei.supply.mes.mdip.wh.genuine_opto"; // 你的 AppId
const std::string appKey = "bWe96ZRDRrxzY2YMHIS5jQ=="; // 你的 AppKey
const std::string topic = "T_EMS_AOI"; // Topic 名称
const std::string tag = "HGZYXG"; // 消息 Tag
const std::string uploadedFilesLog = "uploaded_files.txt"; // 记录已上传文件的日志文件
const int maxRetries = 3; // 最大重试次数

// libcurl 写入回调函数
size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
    size_t totalSize = size * nmemb;
    output->append((char*)contents, totalSize);
    return totalSize;
}

// 配置 libcurl
CURL* ConfigureCurl(const std::string& xmlContent) {
    CURL* curl = curl_easy_init();
    if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, apiUrl.c_str());
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, nullptr); // 设置请求头
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, xmlContent.c_str());
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &xmlContent);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(nullptr, ("X-HW-ID: " + appId).c_str()));
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(nullptr, ("X-HW-APPKEY: " + appKey).c_str()));
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(nullptr, ("MsgTopic: " + topic).c_str()));
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(nullptr, ("MsgTag: " + tag).c_str()));
    }
    return curl;
}

// 发送 HTTP 请求(带重试机制)
std::string SendHttpRequestWithRetry(const std::string& xmlContent) {
    int retryCount = 0;
    while (retryCount < maxRetries) {
        CURL* curl = ConfigureCurl(xmlContent);
        CURLcode res = curl_easy_perform(curl);
        if (res == CURLE_OK) {
            long httpCode = 0;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
            if (httpCode == 200) {
                std::string response;
                curl_easy_cleanup(curl);
                return response;
            }
        }
        retryCount++;
        std::this_thread::sleep_for(std::chrono::seconds(retryCount));
    }
    throw std::runtime_error("HTTP 请求失败");
}

// 读取 XML 文件内容
std::string ReadXmlFile(const std::string& filePath) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file.is_open()) {
        throw std::runtime_error("无法打开文件: " + filePath);
    }
    std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    return content;
}

// 加载已上传的文件记录
std::unordered_set<std::string> LoadUploadedFiles(const std::string& logFilePath) {
    std::unordered_set<std::string> uploadedFiles;
    if (fs::exists(logFilePath)) {
        std::ifstream logFile(logFilePath);
        std::string line;
        while (std::getline(logFile, line)) {
            uploadedFiles.insert(line);
        }
    }
    return uploadedFiles;
}

// 主函数
int main() {
    try {
        // 加载已上传的文件记录
        auto uploadedFiles = LoadUploadedFiles(uploadedFilesLog);
        int totalProcessed = 0;
        int totalSuccess = 0;

        std::cout << "开始处理,时间: " << std::chrono::system_clock::now() << std::endl;

        // 遍历 1-19 线
        for (int lineNumber = 1; lineNumber <= 19; lineNumber++) {
            std::string lineFolder = baseFolderPath + "/" + std::to_string(lineNumber) + "线";
            std::string toMesXmlFolder = lineFolder + "/toMesXml";

            // 检查 toMesXml 文件夹是否存在
            if (!fs::exists(toMesXmlFolder)) {
                std::cout << "文件夹 " << toMesXmlFolder << " 不存在,跳过处理。" << std::endl;
                continue;
            }

            // 获取 toMesXml 文件夹中的所有 XML 文件
            std::vector<std::string> xmlFiles;
            for (const auto& entry : fs::directory_iterator(toMesXmlFolder)) {
                if (entry.path().extension() == ".xml") {
                    xmlFiles.push_back(entry.path().string());
                }
            }

            if (xmlFiles.empty()) {
                std::cout << "文件夹 " << toMesXmlFolder << " 中没有 XML 文件。" << std::endl;
                continue;
            }

            std::cout << "发现 " << xmlFiles.size() << " 个XML文件在 " << lineNumber << "线" << std::endl;

            // 遍历每个 XML 文件并发送
            for (const auto& xmlFile : xmlFiles) {
                try {
                    std::string fileName = fs::path(xmlFile).filename().string();
                    totalProcessed++;

                    // 检查文件是否已经上传过
                    if (uploadedFiles.count(fileName)) {
                        std::cout << "文件 " << fileName << " 已经上传过,跳过处理。" << std::endl;
                        continue;
                    }

                    std::cout << "正在处理文件: " << fileName << std::endl;

                    // 读取 XML 文件内容
                    std::string xmlContent = ReadXmlFile(xmlFile);

                    // 发送 HTTP 请求
                    std::string response = SendHttpRequestWithRetry(xmlContent);

                    // 处理响应
                    std::cout << "文件 " << fileName << " 发送成功,服务器响应: " << response << std::endl;
                    totalSuccess++;

                    // 记录已上传的文件名
                    uploadedFiles.insert(fileName);
                    std::ofstream logFile(uploadedFilesLog, std::ios::app);
                    logFile << fileName << std::endl;
                } catch (const std::exception& ex) {
                    std::cerr << "文件 " << xmlFile << " 发生错误: " << ex.what() << std::endl;
                }
            }
        }

        std::cout << "处理完成,总共处理: " << totalProcessed << " 个文件,成功: " << totalSuccess << " 个,时间: "
                  << std::chrono::system_clock::now() << std::endl;
    } catch (const std::exception& ex) {
        std::cerr << "程序执行过程中发生错误: " << ex.what() << std::endl;
    }

    return 0;
}

代码改写成面向对象的风格,可以更好地组织代码结构、提高可读性和可维护性。以下是改写后的版本:

设计说明

  1. AppConfig

    • 用于集中管理配置参数。
    • 提高代码的可维护性和可扩展性。
  2. HttpRequest

    • 封装了与 HTTP 请求相关的逻辑。
    • 包括发送请求、配置 libcurl 和处理回调。
  3. FileProcessor

    • 负责文件的读取和日志记录。
    • 将文件操作独立出来,便于复用和测试。
  4. XmlUploader

    • 主逻辑类,负责遍历文件夹、处理文件并调用其他类的功能。
    • 使用 totalProcessed 和 totalSuccess 记录统计信息。
  5. 主函数

    • 创建 XmlUploader 对象并调用其 run 方法启动程序。

优点

  • 模块化:每个类负责一个特定的功能,职责清晰。
  • 可扩展性:如果需要修改某个功能(如增加新的文件格式支持),只需修改对应类。
  • 易测试性:每个类可以单独进行单元测试。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <unordered_set>
#include <filesystem>
#include <chrono>
#include <thread>
#include <curl/curl.h>

namespace fs = std::filesystem;

// 配置参数类
class AppConfig {
public:
    static const std::string baseFolderPath;
    static const std::string apiUrl;
    static const std::string appId;
    static const std::string appKey;
    static const std::string topic;
    static const std::string tag;
    static const std::string uploadedFilesLog;
    static const int maxRetries;
};

const std::string AppConfig::baseFolderPath = "Z:/彩盒CCD";
const std::string AppConfig::apiUrl = "https://apigw-cn-south.huawei.com/api/mqs/message";
const std::string AppConfig::appId = "huawei.supply.mes.mdip.wh.genuine_opto";
const std::string AppConfig::appKey = "bWe96ZRDRrxzY2YMHIS5jQ==";
const std::string AppConfig::topic = "T_EMS_AOI";
const std::string AppConfig::tag = "HGZYXG";
const std::string AppConfig::uploadedFilesLog = "uploaded_files.txt";
const int AppConfig::maxRetries = 3;

// HTTP 请求类
class HttpRequest {
public:
    static std::string sendWithRetry(const std::string& xmlContent) {
        int retryCount = 0;
        while (retryCount < AppConfig::maxRetries) {
            CURL* curl = configureCurl(xmlContent);
            CURLcode res = curl_easy_perform(curl);
            if (res == CURLE_OK) {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                if (httpCode == 200) {
                    std::string response;
                    curl_easy_cleanup(curl);
                    return response;
                }
            }
            retryCount++;
            std::this_thread::sleep_for(std::chrono::seconds(retryCount));
        }
        throw std::runtime_error("HTTP 请求失败");
    }

private:
    static CURL* configureCurl(const std::string& xmlContent) {
        CURL* curl = curl_easy_init();
        if (curl) {
            curl_easy_setopt(curl, CURLOPT_URL, AppConfig::apiUrl.c_str());
            struct curl_slist* headers = nullptr;
            headers = curl_slist_append(headers, ("X-HW-ID: " + AppConfig::appId).c_str());
            headers = curl_slist_append(headers, ("X-HW-APPKEY: " + AppConfig::appKey).c_str());
            headers = curl_slist_append(headers, ("MsgTopic: " + AppConfig::topic).c_str());
            headers = curl_slist_append(headers, ("MsgTag: " + AppConfig::tag).c_str());
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, xmlContent.c_str());
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &xmlContent);
        }
        return curl;
    }

    static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
};

// 文件处理类
class FileProcessor {
public:
    static std::string readFile(const std::string& filePath) {
        std::ifstream file(filePath, std::ios::binary);
        if (!file.is_open()) {
            throw std::runtime_error("无法打开文件: " + filePath);
        }
        return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    }

    static std::unordered_set<std::string> loadUploadedFiles(const std::string& logFilePath) {
        std::unordered_set<std::string> uploadedFiles;
        if (fs::exists(logFilePath)) {
            std::ifstream logFile(logFilePath);
            std::string line;
            while (std::getline(logFile, line)) {
                uploadedFiles.insert(line);
            }
        }
        return uploadedFiles;
    }

    static void logUploadedFile(const std::string& fileName, const std::string& logFilePath) {
        std::ofstream logFile(logFilePath, std::ios::app);
        logFile << fileName << std::endl;
    }
};

// 主逻辑类
class XmlUploader {
public:
    XmlUploader() : totalProcessed(0), totalSuccess(0) {}

    void run() {
        try {
            auto uploadedFiles = FileProcessor::loadUploadedFiles(AppConfig::uploadedFilesLog);
            std::cout << "开始处理,时间: " << std::chrono::system_clock::now() << std::endl;

            for (int lineNumber = 1; lineNumber <= 19; lineNumber++) {
                processLine(lineNumber, uploadedFiles);
            }

            std::cout << "处理完成,总共处理: " << totalProcessed << " 个文件,成功: " << totalSuccess << " 个,时间: "
                      << std::chrono::system_clock::now() << std::endl;
        } catch (const std::exception& ex) {
            std::cerr << "程序执行过程中发生错误: " << ex.what() << std::endl;
        }
    }

private:
    int totalProcessed;
    int totalSuccess;

    void processLine(int lineNumber, std::unordered_set<std::string>& uploadedFiles) {
        std::string lineFolder = AppConfig::baseFolderPath + "/" + std::to_string(lineNumber) + "线";
        std::string toMesXmlFolder = lineFolder + "/toMesXml";

        if (!fs::exists(toMesXmlFolder)) {
            std::cout << "文件夹 " << toMesXmlFolder << " 不存在,跳过处理。" << std::endl;
            return;
        }

        std::vector<std::string> xmlFiles;
        for (const auto& entry : fs::directory_iterator(toMesXmlFolder)) {
            if (entry.path().extension() == ".xml") {
                xmlFiles.push_back(entry.path().string());
            }
        }

        if (xmlFiles.empty()) {
            std::cout << "文件夹 " << toMesXmlFolder << " 中没有 XML 文件。" << std::endl;
            return;
        }

        std::cout << "发现 " << xmlFiles.size() << " 个XML文件在 " << lineNumber << "线" << std::endl;

        for (const auto& xmlFile : xmlFiles) {
            processFile(xmlFile, uploadedFiles);
        }
    }

    void processFile(const std::string& xmlFile, std::unordered_set<std::string>& uploadedFiles) {
        try {
            std::string fileName = fs::path(xmlFile).filename().string();
            totalProcessed++;

            if (uploadedFiles.count(fileName)) {
                std::cout << "文件 " << fileName << " 已经上传过,跳过处理。" << std::endl;
                return;
            }

            std::cout << "正在处理文件: " << fileName << std::endl;

            std::string xmlContent = FileProcessor::readFile(xmlFile);
            std::string response = HttpRequest::sendWithRetry(xmlContent);

            std::cout << "文件 " << fileName << " 发送成功,服务器响应: " << response << std::endl;
            totalSuccess++;

            uploadedFiles.insert(fileName);
            FileProcessor::logUploadedFile(fileName, AppConfig::uploadedFilesLog);
        } catch (const std::exception& ex) {
            std::cerr << "文件 " << xmlFile << " 发生错误: " << ex.what() << std::endl;
        }
    }
};

// 主函数
int main() {
    XmlUploader uploader;
    uploader.run();
    return 0;
}

    用C++和QT代码编译:

    #include <QCoreApplication>
    #include <QFile>
    #include <QDir>
    #include <QTextStream>
    #include <QNetworkAccessManager>
    #include <QNetworkReply>
    #include <QEventLoop>
    #include <QXmlStreamReader>
    #include <QSet>
    #include <QDateTime>
    #include <QDebug>
    #include <QThread>
    
    class EMSUploader : public QObject {
        Q_OBJECT
    
    public:
        explicit EMSUploader(QObject *parent = nullptr) : QObject(parent), maxRetries(3) {}
    
        void start(const QString &baseFolderPath, const QString &apiUrl,
                   const QString &appId, const QString &appKey,
                   const QString &topic, const QString &tag, const QString &uploadedFilesLog)
        {
            this->baseFolderPath = baseFolderPath;
            this->apiUrl = apiUrl;
            this->appId = appId;
            this->appKey = appKey;
            this->topic = topic;
            this->tag = tag;
            this->uploadedFilesLog = uploadedFilesLog;
    
            uploadedFiles = loadUploadedFiles(uploadedFilesLog);
            qDebug() << "开始处理,时间:" << QDateTime::currentDateTime().toString();
    
            processLines();
        }
    
    private:
        void processLines()
        {
            for (int lineNumber = 1; lineNumber <= 19; ++lineNumber) {
                QString lineFolder = QDir(baseFolderPath).absoluteFilePath(QString::number(lineNumber) + "线");
                QString toMesXmlFolder = QDir(lineFolder).absoluteFilePath("toMesXml");
    
                if (!QDir(toMesXmlFolder).exists()) {
                    qDebug() << "文件夹" << toMesXmlFolder << "不存在,跳过处理。";
                    continue;
                }
    
                QStringList xmlFiles = QDir(toMesXmlFolder).entryList({"*.xml"}, QDir::Files);
                if (xmlFiles.isEmpty()) {
                    qDebug() << "文件夹" << toMesXmlFolder << "中没有XML文件。";
                    continue;
                }
    
                qDebug() << "发现" << xmlFiles.size() << "个XML文件在" << lineNumber << "线";
    
                foreach (const QString &xmlFile, xmlFiles) {
                    QString filePath = QDir(toMesXmlFolder).absoluteFilePath(xmlFile);
                    processFile(filePath);
                }
            }
    
            qDebug() << "处理完成,总共处理: " << totalProcessed << "个文件,成功: " << totalSuccess << "个,时间:"
                     << QDateTime::currentDateTime().toString();
        }
    
        void processFile(const QString &filePath)
        {
            QString fileName = QFileInfo(filePath).fileName();
            if (uploadedFiles.contains(fileName)) {
                qDebug() << "文件" << fileName << "已经上传过,跳过处理。";
                return;
            }
    
            qDebug() << "正在处理文件:" << fileName;
    
            QString xmlContent = readXmlFile(filePath);
    
            trySendRequestWithRetry(xmlContent, filePath);
        }
    
        QString readXmlFile(const QString &filePath)
        {
            QFile file(filePath);
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                qWarning() << "无法打开XML文件:" << filePath;
                return QString();
            }
    
            QTextStream in(&file);
            QString content = in.readAll();
            file.close();
            return content;
        }
    
        void trySendRequestWithRetry(const QString &xmlContent, const QString &filePath)
        {
            int retryCount = 0;
            while (retryCount < maxRetries) {
                bool success = sendHttpRequest(xmlContent);
                if (success) break;
    
                retryCount++;
                qDebug() << "请求失败,等待后进行第" << retryCount << "次重试...";
                QThread::msleep(1000 * retryCount); // 注意:这会阻塞当前线程
            }
    
            if (retryCount >= maxRetries) {
                qWarning() << "在" << maxRetries << "次尝试后仍然失败";
                return;
            }
    
            // 假设发送成功
            totalProcessed++;
            totalSuccess++;
            uploadedFiles.insert(QFileInfo(filePath).fileName());
    
            appendToFile(uploadedFilesLog, QFileInfo(filePath).fileName() + "\n");
        }
    
        bool sendHttpRequest(const QString &xmlContent)
        {
            // 使用大括号初始化 QNetworkRequest 对象
            QNetworkRequest request{QUrl(apiUrl)};
            request.setRawHeader("X-HW-ID", appId.toUtf8());
            request.setRawHeader("X-HW-APPKEY", appKey.toUtf8());
            request.setRawHeader("MsgTopic", topic.toUtf8());
            request.setRawHeader("MsgTag", tag.toUtf8());
            request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml");
    
            QNetworkAccessManager manager;
            QEventLoop loop;
    
            QNetworkReply *reply = manager.post(request, xmlContent.toUtf8());
    
            connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
            loop.exec(); // 等待请求完成
    
            if (reply->error() == QNetworkReply::NoError) {
                qDebug() << "文件发送成功,服务器响应:" << reply->readAll();
                reply->deleteLater();
                return true;
            } else {
                qDebug() << "请求错误:" << reply->errorString();
                reply->deleteLater();
                return false;
            }
        }
    
        QSet<QString> loadUploadedFiles(const QString &logFilePath)
        {
            QSet<QString> files;
            QFile file(logFilePath);
            if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                QTextStream in(&file);
                while (!in.atEnd()) {
                    files.insert(in.readLine().trimmed());
                }
                qDebug() << "已加载" << files.size() << "个已上传文件记录";
                file.close();
            } else {
                qDebug() << "上传记录文件" << logFilePath << "不存在,将创建新文件";
            }
            return files;
        }
    
        void appendToFile(const QString &filePath, const QString &content)
        {
            QFile file(filePath);
            if (file.open(QIODevice::Append | QIODevice::Text)) {
                QTextStream out(&file);
                out << content;
                file.flush();
                file.close();
            } else {
                qWarning() << "无法追加写入文件:" << filePath;
            }
        }
    
    private:
        QString baseFolderPath;
        QString apiUrl;
        QString appId;
        QString appKey;
        QString topic;
        QString tag;
        QString uploadedFilesLog;
        QSet<QString> uploadedFiles;
        int maxRetries;
        int totalProcessed = 0;
        int totalSuccess = 0;
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        EMSUploader uploader;
        uploader.start("Z:/彩盒CCD", "https://apigw-cn-south.huawei.com/api/mqs/message",
                       "huawei.supply.mes.mdip.wh.genuine_opto", "bWe96ZRDRrxzY2YMHIS5jQ==",
                       "T_EMS_AOI", "HGZYXG", "uploaded_files.txt");
    
        return a.exec();
    }
    
    #include "main.moc"
    

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包

    打赏作者

    小范好好学习

    你的鼓励将是我创作的最大动力

    ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

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

    余额充值