当前位置: 首页 > news >正文

C#批量压缩并上载CSV数据文件到Box企业云盘

C# .NET 8实现Windows下批量压缩csv文件为zip文件,然后异步上传到box企业云服务网盘路径,实现异常处理和写入运行状态日志,参数来自ini配置文件。

C# .NET 8代码示例,包含INI配置读取、CSV文件压缩、Box上传、异步处理和日志记录功能:

using System.Collections.Concurrent;
using System.IO.Compression;
using IniParser;
using IniParser.Model;
using Box.V2;
using Box.V2.Auth;
using Box.V2.Config;
using Box.V2.Models;

class Program
{
    private static readonly object _logLock = new object();
    private static string _logPath;

    static async Task Main(string[] args)
    {
        try
        {
            // 读取配置文件
            var config = LoadConfiguration("config.ini");
            
            // 初始化Box客户端
            var boxClient = InitializeBoxClient(config);
            
            // 处理文件
            await ProcessFilesAsync(config, boxClient);
        }
        catch (Exception ex)
        {
            Log($"全局异常: {ex.Message}");
        }
    }

    static Configuration LoadConfiguration(string configPath)
    {
        var parser = new FileIniDataParser();
        IniData iniData = parser.ReadFile(configPath);

        return new Configuration
        {
            ClientId = iniData["BoxConfig"]["ClientId"],
            ClientSecret = iniData["BoxConfig"]["ClientSecret"],
            AccessToken = iniData["BoxConfig"]["AccessToken"],
            UploadFolderId = iniData["BoxConfig"]["UploadFolderId"],
            SourceFolder = iniData["FileConfig"]["SourceFolder"],
            ZipFolder = iniData["FileConfig"]["ZipFolder"],
            LogPath = iniData["FileConfig"]["LogPath"]
        };
    }

    static BoxClient InitializeBoxClient(Configuration config)
    {
        _logPath = config.LogPath;
        
        var auth = new OAuthSession(config.AccessToken, "N/A", 3600, "bearer");
        var boxConfig = new BoxConfigBuilder(config.ClientId, config.ClientSecret, new Uri("http://localhost")).Build();
        return new BoxClient(boxConfig, auth);
    }

    static async Task ProcessFilesAsync(Configuration config, BoxClient boxClient)
    {
        try
        {
            Directory.CreateDirectory(config.ZipFolder);
            Directory.CreateDirectory(Path.GetDirectoryName(_logPath));

            var csvFiles = Directory.GetFiles(config.SourceFolder, "*.csv");
            Log($"找到 {csvFiles.Length} 个CSV文件需要处理");

            var tasks = new ConcurrentBag<Task>();
            
            Parallel.ForEach(csvFiles, csvFile =>
            {
                tasks.Add(ProcessSingleFileAsync(csvFile, config, boxClient));
            });

            await Task.WhenAll(tasks);
            Log("所有文件处理完成");
        }
        catch (Exception ex)
        {
            Log($"文件处理异常: {ex.Message}");
        }
    }

    static async Task ProcessSingleFileAsync(string csvFile, Configuration config, BoxClient boxClient)
    {
        try
        {
            string zipFileName = $"{Path.GetFileNameWithoutExtension(csvFile)}_{DateTime.Now:yyyyMMddHHmmss}.zip";
            string zipPath = Path.Combine(config.ZipFolder, zipFileName);

            // 压缩文件
            CreateZipFile(csvFile, zipPath);
            Log($"文件 {Path.GetFileName(csvFile)} 压缩成功");

            // 上传到Box
            await UploadToBoxAsync(boxClient, zipPath, config.UploadFolderId);
            Log($"文件 {zipFileName} 上传成功");

            // 清理临时压缩文件(可选)
            File.Delete(zipPath);
        }
        catch (Exception ex)
        {
            Log($"处理文件 {Path.GetFileName(csvFile)} 失败: {ex.Message}");
        }
    }

    static void CreateZipFile(string sourceFile, string zipPath)
    {
        using (var zipArchive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
        {
            zipArchive.CreateEntryFromFile(sourceFile, Path.GetFileName(sourceFile));
        }
    }

    static async Task UploadToBoxAsync(BoxClient client, string filePath, string folderId)
    {
        using (var fileStream = new FileStream(filePath, FileMode.Open))
        {
            var fileRequest = new BoxFileRequest
            {
                Name = Path.GetFileName(filePath),
                Parent = new BoxRequestEntity { Id = folderId }
            };

            await client.FilesManager.UploadAsync(fileRequest, fileStream);
        }
    }

    static void Log(string message)
    {
        string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}";
        
        lock (_logLock)
        {
            File.AppendAllText(_logPath, logEntry + Environment.NewLine);
        }
    }
}

public class Configuration
{
    public string ClientId { get; set; }
    public string ClientSecret { get; set; }
    public string AccessToken { get; set; }
    public string UploadFolderId { get; set; }
    public string SourceFolder { get; set; }
    public string ZipFolder { get; set; }
    public string LogPath { get; set; }
}

实现说明:

  1. 配置管理:

    • 使用IniParser包读取INI配置文件
    • 配置参数包括Box认证信息、文件路径和日志路径
    • Configuration类用于存储配置参数
  2. Box客户端初始化:

    • 使用OAuth 2.0认证
    • 需要有效的访问令牌(AccessToken)
  3. 文件处理:

    • 使用并行处理加速文件压缩(Parallel.ForEach)
    • 每个文件生成带时间戳的唯一ZIP文件名
    • 自动清理临时压缩文件(可选)
  4. 异步上传:

    • 使用Box官方SDK的异步上传方法
    • 支持大文件分块上传(SDK自动处理)
  5. 日志记录:

    • 线程安全的日志写入机制
    • 包含时间戳和详细操作记录
    • 支持并发写入时的文件锁定
  6. 异常处理:

    • 多层异常捕获(全局、文件处理、单个文件)
    • 详细的错误信息记录

配置示例(config.ini):

[BoxConfig]
ClientId = your_client_id
ClientSecret = your_client_secret
AccessToken = your_access_token
UploadFolderId = 0

[FileConfig]
SourceFolder = C:\CSVFiles
ZipFolder = C:\TempZips
LogPath = C:\Logs\upload.log

注意事项:

  1. Box认证:

    • 需要有效的Box开发者账号和企业配置
    • 建议使用JWT认证代替直接访问令牌(需修改认证逻辑)
  2. 性能优化:

    • 根据网络情况调整并行处理数量
    • 添加重试逻辑处理网络波动
  3. 安全增强:

    • 敏感信息(如ClientSecret)建议加密存储
    • 使用配置文件权限控制
  4. 扩展功能:

    • 添加文件校验(MD5校验和)
    • 实现增量上传功能
    • 添加压缩密码保护
  5. 错误处理:

    • 添加不同异常类型的处理逻辑
    • 实现死信队列处理持续失败文件

使用时需要安装以下NuGet包:

  • ini-parser
  • Box.V2

安装包和发布Release版程序的脚本:

cd <.csproj文件所在的目录>
dotnet add package Box.V2
dotnet add package ini-parser
dotnet build <.csproj文件完整路径> /property:GenerateFullPaths=true /consoleloggerparameters:NoSummary /p:Configuration=Release /p:Platform="AnyCPU"

相关文章:

  • 统一数据返回格式
  • IDEA入门及常用快捷键
  • AI-Deepseek + PPT
  • 用Python之requests库调用大模型API实现多轮对话
  • Vulnhub-Hackme靶机
  • centos7服务器 Java和Hadoop安装教程,用VMware和finalshell
  • 2025东方财富笔试考什么?cata能力测评攻略|答题技巧真题分享
  • 浙江省一体化数字资源系统(IRS)介绍(七个方面展开)
  • PHP之字符串拼接
  • vscode远程ssh链接服务器
  • 内网环境下如何快速下载大模型
  • 【Python爬虫】利用代理IP爬取跨境电商AI选品分析
  • 3.4刷题
  • RS485总线为什么要加终端电阻?
  • Blazor-路由模板(下)
  • 如何在Spring Boot中读取JAR包内resources目录下文件
  • C++查看动态库导出哪些函数以及动态库导出形式
  • vLLM代码推理Qwen2-VL多模态
  • 华为配置篇-OSPF基础实验
  • 【RabbitMQ】Producer之TTL过期时间 - 基于AMQP 0-9-1
  • 体坛联播|博洛尼亚时隔51年再夺意杯,皇马逆转马洛卡
  • 美国明尼苏达州发生山火,过火面积超80平方公里
  • 美国4月CPI同比上涨2.3%低于预期,为2021年2月来最小涨幅
  • 从普通人经历中发现历史,王笛解读《线索与痕迹》
  • 通辽警方侦破一起积压21年的命案:嫌疑人企图强奸遭反抗后杀人
  • 国内首例侵入式脑机接口系统前瞻性临床试验:受试者已能用意念玩游戏