C# 文件分割与合并工具设计与实现

一、系统概述

文件分割与合并是数据管理中的基础操作,常用于大文件传输(如邮件附件限制)、分布式存储(拆分后存储至多个介质)、数据备份(分卷压缩)等场景。本工具基于 C# 语言开发,利用 .NET FrameworkSystem.IO命名空间实现二进制文件流操作,支持按大小分割(如每 1MB/10MB 一个文件)和按序号合并,具备跨平台(Windows/Linux/macOS via .NET Core)、高可靠性(异常捕获、校验机制)和易用性(命令行/GUI 双模式)特点。

二、核心设计思路

2.1 分割策略

  • 按固定大小分割 :将源文件拆分为多个指定大小(如 chunkSize = 1024 * 1024字节,即 1MB)的子文件,最后一个子文件可能小于指定大小。
  • 文件命名规则 :子文件命名为 原文件名.partN(N 为序号,从 1 开始),如 largefile.zip.part1largefile.zip.part2
  • 元数据记录 (可选):生成 原文件名.info文件,记录源文件大小、分割数量、校验和(如 MD5),用于合并时校验完整性。

2.2 合并策略

  • 按序号合并 :读取所有 原文件名.partN子文件,按序号从小到大拼接为完整文件。
  • 完整性校验:通过比对子文件数量、总大小或 MD5 校验和,确保合并后文件与源文件一致。

三、实现步骤与代码

3.1 开发环境

  • 语言:C# 9.0+
  • 框架:.NET 6.0(跨平台支持)
  • 工具:Visual Studio 2022 / Visual Studio Code
  • 核心类库System.IO(文件流)、System.Security.Cryptography(MD5 校验)

3.2 文件分割实现

3.2.1 核心函数:SplitFile
csharp 复制代码
using System;
using System.IO;
using System.Security.Cryptography;

public class FileSplitter
{
    /// <summary>
    /// 分割文件为多个子文件
    /// </summary>
    /// <param name="sourcePath">源文件路径</param>
    /// <param name="outputDir">输出目录(默认当前目录)</param>
    /// <param name="chunkSize">子文件大小(字节,默认 1MB)</param>
    public static void SplitFile(string sourcePath, string outputDir = ".", long chunkSize = 1024 * 1024)
    {
        // 校验源文件
        if (!File.Exists(sourcePath))
            throw new FileNotFoundException("源文件不存在", sourcePath);
        
        // 创建输出目录
        Directory.CreateDirectory(outputDir);
        string fileName = Path.GetFileNameWithoutExtension(sourcePath);
        string fileExt = Path.GetExtension(sourcePath);
        string infoPath = Path.Combine(outputDir, $"{fileName}.info");

        using (FileStream sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
        {
            long fileSize = sourceStream.Length;
            int partCount = (int)Math.Ceiling((double)fileSize / chunkSize);
            byte[] buffer = new byte[chunkSize];

            // 写入 info 文件(记录元数据)
            using (StreamWriter infoWriter = new StreamWriter(infoPath))
            {
                infoWriter.WriteLine($"SourceFile: {Path.GetFileName(sourcePath)}");
                infoWriter.WriteLine($"FileSize: {fileSize}");
                infoWriter.WriteLine($"PartCount: {partCount}");
                infoWriter.WriteLine($"ChunkSize: {chunkSize}");
                infoWriter.WriteLine($"MD5: {CalculateMD5(sourceStream)}"); // 计算源文件 MD5
            }

            // 分割文件
            for (int i = 0; i < partCount; i++)
            {
                long position = i * chunkSize;
                int bytesToRead = (int)Math.Min(chunkSize, fileSize - position);
                sourceStream.Seek(position, SeekOrigin.Begin);
                int bytesRead = sourceStream.Read(buffer, 0, bytesToRead);

                string partPath = Path.Combine(outputDir, $"{fileName}{fileExt}.part{i + 1}");
                using (FileStream partStream = new FileStream(partPath, FileMode.Create, FileAccess.Write))
                {
                    partStream.Write(buffer, 0, bytesRead);
                }
                Console.WriteLine($"已创建: {partPath} ({bytesRead} 字节)");
            }
        }
        Console.WriteLine($"分割完成,共 {partCount} 个子文件,保存至: {outputDir}");
    }

    // 计算文件 MD5 校验和
    private static string CalculateMD5(FileStream stream)
    {
        using (MD5 md5 = MD5.Create())
        {
            byte[] hash = md5.ComputeHash(stream);
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

3.3 文件合并实现

3.3.1 核心函数:MergeFiles
csharp 复制代码
public class FileMerger
{
    /// <summary>
    /// 合并子文件为完整文件
    /// </summary>
    /// <param name="partDir">子文件目录(含 .partN 文件)</param>
    /// <param name="outputPath">合并后文件路径</param>
    /// <param name="originalName">原文件名(用于匹配子文件,如 "largefile.zip")</param>
    public static void MergeFiles(string partDir, string outputPath, string originalName)
    {
        string fileExt = Path.GetExtension(originalName);
        string pattern = $"{Path.GetFileNameWithoutExtension(originalName)}{fileExt}.part*";
        string[] partFiles = Directory.GetFiles(partDir, pattern, SearchOption.TopDirectoryOnly);
        
        // 按序号排序(如 part1、part2...)
        Array.Sort(partFiles, (a, b) => 
            int.Parse(Path.GetFileName(a).Split('.')[0].Substring(originalName.Length + fileExt.Length + 1)) 
            .CompareTo(int.Parse(Path.GetFileName(b).Split('.')[0].Substring(originalName.Length + fileExt.Length + 1)))
        );

        if (partFiles.Length == 0)
            throw new FileNotFoundException("未找到子文件", pattern);

        // 合并文件
        using (FileStream outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
        {
            foreach (string partPath in partFiles)
            {
                using (FileStream partStream = new FileStream(partPath, FileMode.Open, FileAccess.Read))
                {
                    partStream.CopyTo(outputStream); // 高效复制流
                }
                Console.WriteLine($"已合并: {partPath}");
            }
        }
        Console.WriteLine($"合并完成: {outputPath}");
    }
}

3.4 主程序(命令行交互)

csharp 复制代码
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("C# 文件分割与合并工具");
        Console.WriteLine("1. 分割文件");
        Console.WriteLine("2. 合并文件");
        Console.Write("请选择操作 (1/2): ");
        string choice = Console.ReadLine();

        try
        {
            if (choice == "1")
            {
                Console.Write("源文件路径: ");
                string source = Console.ReadLine();
                Console.Write("子文件大小 (MB,默认 1): ");
                int mb = int.TryParse(Console.ReadLine(), out int m) ? m : 1;
                FileSplitter.SplitFile(source, chunkSize: mb * 1024 * 1024);
            }
            else if (choice == "2")
            {
                Console.Write("子文件目录: ");
                string partDir = Console.ReadLine();
                Console.Write("原文件名 (如 largefile.zip): ");
                string originalName = Console.ReadLine();
                Console.Write("合并后文件路径: ");
                string output = Console.ReadLine();
                FileMerger.MergeFiles(partDir, output, originalName);
            }
            else
            {
                Console.WriteLine("无效选择");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"错误: {ex.Message}");
        }
    }
}

参考代码 C#-文件分割与合并 www.youwenfan.com/contentcss/123123.html

四、关键技术点

4.1 二进制流高效处理

  • 使用 FileStreamSeek方法定位文件位置,避免全文件加载至内存。
  • 通过 CopyTo方法(.NET 4.0+)实现流的高效复制,减少缓冲区操作。

4.2 异常处理与校验

  • 文件不存在 :抛出 FileNotFoundException并提示路径。
  • 权限不足 :捕获 UnauthorizedAccessException,建议以管理员身份运行。
  • MD5 校验 :合并后对比源文件与合并文件的 MD5 值,确保数据一致性(示例中已记录源文件 MD5 至 .info文件)。

4.3 跨平台兼容性

  • 使用 Path.Combine处理路径分隔符(\/),适配 Windows/Linux/macOS。
  • 通过 .NET Core 运行时实现跨平台部署(需安装对应 SDK)。

五、扩展功能建议

  1. 图形界面(GUI):使用 WPF 或 WinForms 开发可视化界面,支持拖拽文件、进度条显示。
  2. 加密分割:分割时对子文件进行 AES 加密,合并时解密(需密钥管理)。
  3. 多线程处理:分割/合并时用多线程并行处理子文件,提升大文件操作效率。
  4. 云存储集成:分割后自动上传子文件至 FTP/SFTP 服务器,合并时从云端下载。
相关推荐
萝卜白菜。4 分钟前
TongWeb7.0相同的类指明加载顺序
开发语言·python·pycharm
wb043072014 分钟前
使用 Java 开发 MCP 服务并发布到 Maven 中央仓库完整指南
java·开发语言·spring boot·ai·maven
Rsun045515 分钟前
设计模式应该怎么学
java·开发语言·设计模式
良木生香22 分钟前
【C++初阶】:C++类和对象(下):构造函数promax & 类型转换 & static & 友元 & 内部类 & 匿名对象 & 超级优化
c语言·开发语言·c++
5系暗夜孤魂28 分钟前
系统越复杂,越需要“边界感”:从 Java 体系理解大型工程的可维护性本质
java·开发语言
无巧不成书02181 小时前
C语言零基础速通指南 | 1小时从入门到跑通完整项目
c语言·开发语言·编程实战·c语言入门·零基础编程·c语言速通
三雷科技1 小时前
使用 `dlopen` 动态加载 `.so` 文件
开发语言·c++·算法
wellc2 小时前
java进阶知识点
java·开发语言
听风吹等浪起2 小时前
用Python和Pygame从零实现坦克大战
开发语言·python·pygame
灰色小旋风2 小时前
力扣合并K个升序链表C++
java·开发语言