最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于C#實(shí)現(xiàn)的文件分割與合并工具

 更新時(shí)間:2026年04月08日 09:30:01   作者:fie8889  
文件分割與合并是數(shù)據(jù)管理中的基礎(chǔ)操作,常用于大文件傳輸(如郵件附件限制)、分布式存儲(chǔ)(拆分后存儲(chǔ)至多個(gè)介質(zhì))、數(shù)據(jù)備份(分卷壓縮)等場(chǎng)景,本工具基于 C# 語(yǔ)言開發(fā)實(shí)現(xiàn)的文件分割與合并工具,需要的朋友可以參考下

一、系統(tǒng)概述

文件分割與合并是數(shù)據(jù)管理中的常見操作,廣泛應(yīng)用于以下場(chǎng)景:

  • 大文件傳輸:突破郵件附件大小限制(如將 50MB 文件分割為 5×10MB)
  • 分布式存儲(chǔ):將文件拆分后存儲(chǔ)至多個(gè)磁盤或云存儲(chǔ)節(jié)點(diǎn)
  • 分卷備份:配合壓縮算法實(shí)現(xiàn)分卷壓縮備份
  • 斷點(diǎn)續(xù)傳:支持文件的分塊上傳與下載

本工具基于 C# 語(yǔ)言開發(fā),采用 .NET 6.0 運(yùn)行時(shí),利用 System.IO 命名空間實(shí)現(xiàn)二進(jìn)制文件流操作。核心特性包括:

  • ? 按固定大小分割(支持自定義分塊大?。?/li>
  • ? 按序號(hào)自動(dòng)合并
  • ? 完整性校驗(yàn)(MD5 校驗(yàn)和)
  • ? 跨平臺(tái)支持(Windows / Linux / macOS)
  • ? 異常捕獲與友好的錯(cuò)誤提示
  • ? 命令行 / GUI 雙模式支持(GUI 可作為擴(kuò)展)

二、核心設(shè)計(jì)思路

2.1 分割策略

  • 按固定大小分割:將源文件拆分為多個(gè)指定大?。ㄈ?chunkSize = 1024 * 1024字節(jié),即 1MB)的子文件,最后一個(gè)子文件可能小于指定大小。
  • 文件命名規(guī)則:子文件命名為 原文件名.partN(N 為序號(hào),從 1 開始),如 largefile.zip.part1largefile.zip.part2。
  • 元數(shù)據(jù)記錄(可選):生成 原文件名.info文件,記錄源文件大小、分割數(shù)量、校驗(yàn)和(如 MD5),用于合并時(shí)校驗(yàn)完整性。
SourceFile: archive.zip
FileSize: 104857600
PartCount: 10
ChunkSize: 1048576
MD5: a1b2c3d4e5f6...

2.2 合并策略

  • 按序號(hào)合并:讀取所有 原文件名.partN子文件,按序號(hào)從小到大拼接為完整文件。
  • 完整性校驗(yàn):通過比對(duì)子文件數(shù)量、總大小或 MD5 校驗(yàn)和,確保合并后文件與源文件一致。

三、實(shí)現(xiàn)步驟與代碼

3.1 開發(fā)環(huán)境

  • 語(yǔ)言:C# 9.0+
  • 框架:.NET 6.0(跨平臺(tái)支持)
  • 工具:Visual Studio 2022 / Visual Studio Code
  • 核心類庫(kù)System.IO(文件流)、System.Security.Cryptography(MD5 校驗(yàn))

3.2 文件分割實(shí)現(xiàn)

3.2.1 核心函數(shù):SplitFile

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class FileSplitter
{
    /// <summary>
    /// 分割文件為多個(gè)子文件
    /// </summary>
    /// <param name="sourcePath">源文件路徑</param>
    /// <param name="outputDir">輸出目錄(默認(rèn)源文件所在目錄)</param>
    /// <param name="chunkSizeBytes">子文件大?。ㄗ止?jié),默認(rèn) 1MB)</param>
    /// <param name="generateInfoFile">是否生成 .info 元數(shù)據(jù)文件</param>
    /// <returns>分割后的子文件數(shù)量</returns>
    public static int SplitFile(string sourcePath, string outputDir = null, 
        long chunkSizeBytes = 1024 * 1024, bool generateInfoFile = true)
    {
        // 參數(shù)校驗(yàn)
        if (!File.Exists(sourcePath))
            throw new FileNotFoundException($"源文件不存在: {sourcePath}");
        if (chunkSizeBytes <= 0)
            throw new ArgumentException("分塊大小必須大于 0", nameof(chunkSizeBytes));
        // 確定輸出目錄
        outputDir ??= Path.GetDirectoryName(sourcePath);
        Directory.CreateDirectory(outputDir);
        string fileName = Path.GetFileName(sourcePath);
        string baseName = Path.GetFileNameWithoutExtension(sourcePath);
        string extension = Path.GetExtension(sourcePath);
        string fullBaseName = baseName + extension;
        // 計(jì)算 MD5(需要在讀取流之前計(jì)算,或重新打開流)
        string md5Hash = string.Empty;
        if (generateInfoFile)
            md5Hash = CalculateFileMD5(sourcePath);
        using (FileStream sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
        {
            long fileSize = sourceStream.Length;
            int partCount = (int)Math.Ceiling((double)fileSize / chunkSizeBytes);
            byte[] buffer = new byte[chunkSizeBytes];
            // 生成元數(shù)據(jù)文件
            if (generateInfoFile)
            {
                string infoPath = Path.Combine(outputDir, $"{fullBaseName}.info");
                using (StreamWriter infoWriter = new StreamWriter(infoPath, false, Encoding.UTF8))
                {
                    infoWriter.WriteLine($"SourceFile: {fileName}");
                    infoWriter.WriteLine($"FileSize: {fileSize}");
                    infoWriter.WriteLine($"PartCount: {partCount}");
                    infoWriter.WriteLine($"ChunkSize: {chunkSizeBytes}");
                    infoWriter.WriteLine($"MD5: {md5Hash}");
                    infoWriter.WriteLine($"CreatedAt: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
                }
            }
            // 執(zhí)行分割
            for (int i = 0; i < partCount; i++)
            {
                long position = i * chunkSizeBytes;
                int bytesToRead = (int)Math.Min(chunkSizeBytes, fileSize - position);
                sourceStream.Seek(position, SeekOrigin.Begin);
                int bytesRead = sourceStream.Read(buffer, 0, bytesToRead);
                if (bytesRead != bytesToRead)
                    Console.WriteLine($"警告: 第 {i + 1} 個(gè)分塊實(shí)際讀取 {bytesRead} 字節(jié),預(yù)期 {bytesToRead} 字節(jié)");
                string partPath = Path.Combine(outputDir, $"{fullBaseName}.part{i + 1}");
                using (FileStream partStream = new FileStream(partPath, FileMode.Create, FileAccess.Write))
                {
                    partStream.Write(buffer, 0, bytesRead);
                }
                Console.WriteLine($"[分割] 已創(chuàng)建: {Path.GetFileName(partPath)} ({bytesRead} 字節(jié))");
            }
            Console.WriteLine($"分割完成: {partCount} 個(gè)分塊,輸出目錄: {outputDir}");
            return partCount;
        }
    }
    /// <summary>
    /// 計(jì)算文件的 MD5 校驗(yàn)值
    /// </summary>
    private static string CalculateFileMD5(string filePath)
    {
        using (var md5 = MD5.Create())
        using (var stream = File.OpenRead(filePath))
        {
            byte[] hash = md5.ComputeHash(stream);
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

3.3 文件合并實(shí)現(xiàn)(完整版,含校驗(yàn))

3.3.1 核心函數(shù):MergeFiles

public class FileMerger
{
    /// <summary>
    /// 合并子文件為完整文件
    /// </summary>
    /// <param name="partDirectory">子文件所在目錄</param>
    /// <param name="originalFileName">原文件名(如 "archive.zip")</param>
    /// <param name="outputPath">合并后的輸出路徑</param>
    /// <param name="verifyIntegrity">是否校驗(yàn) MD5(需要 .info 文件)</param>
    /// <returns>合并后的文件大?。ㄗ止?jié))</returns>
    public static long MergeFiles(string partDirectory, string originalFileName, 
        string outputPath, bool verifyIntegrity = true)
    {
        if (!Directory.Exists(partDirectory))
            throw new DirectoryNotFoundException($"目錄不存在: {partDirectory}");
        string extension = Path.GetExtension(originalFileName);
        string baseName = Path.GetFileNameWithoutExtension(originalFileName);
        string fullBaseName = baseName + extension;
        string pattern = $"{fullBaseName}.part*";
        // 獲取并排序分塊文件
        string[] partFiles = Directory.GetFiles(partDirectory, pattern, SearchOption.TopDirectoryOnly);
        if (partFiles.Length == 0)
            throw new FileNotFoundException($"未找到匹配的分塊文件: {pattern}");
        // 按序號(hào)排序(解析 partN 中的 N)
        Array.Sort(partFiles, (a, b) =>
        {
            int indexA = ExtractPartNumber(a, fullBaseName);
            int indexB = ExtractPartNumber(b, fullBaseName);
            return indexA.CompareTo(indexB);
        });
        // 驗(yàn)證序號(hào)連續(xù)性(可選)
        for (int i = 0; i < partFiles.Length; i++)
        {
            int expected = i + 1;
            int actual = ExtractPartNumber(partFiles[i], fullBaseName);
            if (actual != expected)
                throw new InvalidOperationException($"分塊序號(hào)不連續(xù): 期望 {expected},實(shí)際 {actual}");
        }
        // 合并文件
        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($"[合并] 已處理: {Path.GetFileName(partPath)}");
            }
        }
        Console.WriteLine($"合并完成: {outputPath}");
        long mergedSize = new FileInfo(outputPath).Length;
        // 完整性校驗(yàn)
        if (verifyIntegrity)
        {
            string infoPath = Path.Combine(partDirectory, $"{fullBaseName}.info");
            if (File.Exists(infoPath))
            {
                var metadata = ParseInfoFile(infoPath);
                string expectedMd5 = metadata["MD5"];
                string actualMd5 = CalculateFileMD5(outputPath);
                if (string.Equals(expectedMd5, actualMd5, StringComparison.OrdinalIgnoreCase))
                {
                    Console.WriteLine($"[校驗(yàn)] MD5 一致: {actualMd5}");
                }
                else
                {
                    Console.WriteLine($"[警告] MD5 不一致! 期望: {expectedMd5}, 實(shí)際: {actualMd5}");
                }
            }
            else
            {
                Console.WriteLine("[校驗(yàn)] 未找到 .info 文件,跳過 MD5 校驗(yàn)");
            }
        }
        return mergedSize;
    }
    /// <summary>
    /// 從文件名中提取分塊序號(hào)(如 file.zip.part3 → 3)
    /// </summary>
    private static int ExtractPartNumber(string filePath, string fullBaseName)
    {
        string fileName = Path.GetFileNameWithoutExtension(filePath);
        // 文件名格式: fullBaseName.partN
        string suffix = fileName.Substring(fullBaseName.Length + 1); // ".partN" → "partN"
        if (suffix.StartsWith("part", StringComparison.OrdinalIgnoreCase))
        {
            string numberPart = suffix.Substring(4);
            if (int.TryParse(numberPart, out int number))
                return number;
        }
        throw new InvalidOperationException($"無法解析分塊序號(hào): {filePath}");
    }
    private static Dictionary<string, string> ParseInfoFile(string infoPath)
    {
        var dict = new Dictionary<string, string>();
        foreach (var line in File.ReadAllLines(infoPath))
        {
            int colonIndex = line.IndexOf(':');
            if (colonIndex > 0)
            {
                string key = line.Substring(0, colonIndex).Trim();
                string value = line.Substring(colonIndex + 1).Trim();
                dict[key] = value;
            }
        }
        return dict;
    }
    private static string CalculateFileMD5(string filePath)
    {
        using (var md5 = MD5.Create())
        using (var stream = File.OpenRead(filePath))
        {
            byte[] hash = md5.ComputeHash(stream);
            return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
        }
    }
}

3.4 主程序(增強(qiáng)版命令行交互)

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("=== 文件分割/合并工具 v2.0 ===");
        Console.WriteLine("1. 分割文件");
        Console.WriteLine("2. 合并文件");
        Console.Write("請(qǐng)選擇 (1/2): ");
        string choice = Console.ReadLine();
        try
        {
            if (choice == "1")
            {
                Console.Write("源文件路徑: ");
                string source = Console.ReadLine();
                Console.Write("分塊大小 (MB,默認(rèn) 1): ");
                string sizeInput = Console.ReadLine();
                int mb = string.IsNullOrWhiteSpace(sizeInput) ? 1 : int.Parse(sizeInput);
                Console.Write("輸出目錄 (留空則使用源文件目錄): ");
                string outputDir = Console.ReadLine();
                outputDir = string.IsNullOrWhiteSpace(outputDir) ? null : outputDir;
                FileSplitter.SplitFile(source, outputDir, mb * 1024L * 1024L);
            }
            else if (choice == "2")
            {
                Console.Write("分塊文件目錄: ");
                string partDir = Console.ReadLine();
                Console.Write("原文件名 (如 largefile.zip): ");
                string originalName = Console.ReadLine();
                Console.Write("合并后輸出路徑: ");
                string output = Console.ReadLine();
                Console.Write("是否校驗(yàn)完整性 (y/n, 默認(rèn) y): ");
                bool verify = Console.ReadLine()?.ToLower() != "n";
                FileMerger.MergeFiles(partDir, originalName, output, verify);
            }
            else
            {
                Console.WriteLine("無效輸入");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"錯(cuò)誤: {ex.Message}");
            if (ex.InnerException != null)
                Console.WriteLine($"詳細(xì)信息: {ex.InnerException.Message}");
        }
        Console.WriteLine("按任意鍵退出...");
        Console.ReadKey();
    }
}

四、關(guān)鍵技術(shù)點(diǎn)

4.1 二進(jìn)制流高效處理

  • 使用 FileStreamSeek方法定位文件位置,避免全文件加載至內(nèi)存。
  • 通過 CopyTo方法(.NET 4.0+)實(shí)現(xiàn)流的高效復(fù)制,減少緩沖區(qū)操作。

4.2 異常處理與校驗(yàn)

  • 文件不存在:拋出 FileNotFoundException并提示路徑。
  • 權(quán)限不足:捕獲 UnauthorizedAccessException,建議以管理員身份運(yùn)行。
  • MD5 校驗(yàn):合并后對(duì)比源文件與合并文件的 MD5 值,確保數(shù)據(jù)一致性(示例中已記錄源文件 MD5 至 .info文件)。

4.3 跨平臺(tái)兼容性

  • 使用 Path.Combine處理路徑分隔符(\/),適配 Windows/Linux/macOS。
  • 通過 .NET Core 運(yùn)行時(shí)實(shí)現(xiàn)跨平臺(tái)部署(需安裝對(duì)應(yīng) SDK)。

五、性能優(yōu)化建議

緩沖區(qū)調(diào)優(yōu)默認(rèn)緩沖區(qū)為 4KB,大文件可手動(dòng)設(shè)置更大緩沖區(qū):

using (var partStream = new FileStream(partPath, FileMode.Open, FileAccess.Read, FileShare.Read, 81920))

并行處理(分割時(shí))多個(gè)分塊可并行寫入(需注意磁盤 I/O 競(jìng)爭(zhēng)):

Parallel.For(0, partCount, i => { /* 寫入 part i */ });

異步版本使用 ReadAsync / WriteAsync 提升 UI 響應(yīng)性(適用于 GUI 版本)。

六、擴(kuò)展功能建議(可后續(xù)迭代)

功能描述實(shí)現(xiàn)難度
圖形界面(WPF / WinUI)拖拽文件、進(jìn)度條顯示、取消操作
加密分割分塊使用 AES 加密,合并時(shí)解密
壓縮分割分割前使用 GZip 壓縮,減少存儲(chǔ)
云存儲(chǔ)集成分割后自動(dòng)上傳至 S3 / FTP / Azure Blob
斷點(diǎn)續(xù)傳式合并支持部分分塊缺失時(shí)提示
多格式支持支持 .part、.001、.7z.001 等常見分卷格式

七、最佳實(shí)踐與注意事項(xiàng)

  • 磁盤空間要求分割時(shí)輸出目錄需要至少等于源文件大?。缓喜r(shí)目標(biāo)目錄需要至少等于所有分塊大小之和。
  • 文件權(quán)限確保程序?qū)υ茨夸浐洼敵瞿夸浘哂凶x寫權(quán)限(Linux 下注意 chmod 755)。
  • 元數(shù)據(jù)文件重要性強(qiáng)烈建議保留 .info 文件,否則合并時(shí)無法自動(dòng)校驗(yàn)完整性。
  • 并發(fā)安全多線程版本需注意同一文件不可被多個(gè)線程同時(shí)寫入。
  • 單元測(cè)試建議對(duì)核心函數(shù)編寫單元測(cè)試,覆蓋邊界情況(空文件、單分塊、序號(hào)亂序等)。

八、總結(jié)

本文實(shí)現(xiàn)了一個(gè)功能完整、生產(chǎn)可用的文件分割與合并工具,核心特點(diǎn)如下:

  • 分割:按固定大小拆分,生成分塊文件 + 可選元數(shù)據(jù)
  • 合并:自動(dòng)識(shí)別分塊序號(hào),拼接 + 完整性校驗(yàn)
  • 健壯性:異常處理、路徑兼容、序號(hào)連續(xù)性校驗(yàn)
  • 可擴(kuò)展:預(yù)留了加密、壓縮、GUI 等擴(kuò)展接口

該工具可直接集成到備份系統(tǒng)、文件傳輸服務(wù)或作為獨(dú)立命令行工具使用。如需完整項(xiàng)目代碼(含 .csproj、單元測(cè)試、WPF GUI 示例),可進(jìn)一步提供。

相關(guān)文章

最新評(píng)論

巴里| 阿瓦提县| 且末县| 奎屯市| 襄汾县| 诸城市| 辽宁省| 霍林郭勒市| 呼伦贝尔市| 凭祥市| 左贡县| 大庆市| 尉犁县| 平原县| 绥江县| 温泉县| 洛宁县| 东平县| 松潘县| 都匀市| 开鲁县| 南昌县| 盐城市| 井冈山市| 浦东新区| 满城县| 定南县| 镇坪县| 洪江市| 历史| 桃源县| 深水埗区| 五华县| 临沭县| 滨州市| 台南县| 永春县| 乌恰县| 永春县| 鸡东县| 钟山县|