diff --git a/Form1.Designer.cs b/Form1.Designer.cs index 8aa9cc8..f6a4653 100644 --- a/Form1.Designer.cs +++ b/Form1.Designer.cs @@ -32,7 +32,6 @@ this.Path1_Box = new System.Windows.Forms.TextBox(); this.Choose1_Button = new System.Windows.Forms.Button(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); - this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.progressBar1 = new System.Windows.Forms.ProgressBar(); this.Start_Button = new System.Windows.Forms.Button(); @@ -73,14 +72,6 @@ this.Choose1_Button.UseVisualStyleBackColor = true; this.Choose1_Button.Click += new System.EventHandler(this.Choose1_Button_Click); // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 53); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(0, 12); - this.label1.TabIndex = 3; - // // label2 // this.label2.AutoSize = true; @@ -174,10 +165,11 @@ this.Controls.Add(this.Start_Button); this.Controls.Add(this.progressBar1); this.Controls.Add(this.label2); - this.Controls.Add(this.label1); this.Controls.Add(this.Choose1_Button); this.Controls.Add(this.Path1_Box); this.Controls.Add(this.Path_Text); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; this.Name = "MD5Create"; this.Text = "MD5Create"; this.ResumeLayout(false); @@ -191,7 +183,6 @@ private System.Windows.Forms.TextBox Path1_Box; private System.Windows.Forms.Button Choose1_Button; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; - private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.ProgressBar progressBar1; private System.Windows.Forms.Button Start_Button; diff --git a/Form1.cs b/Form1.cs index 1b7b5b5..a01df64 100644 --- a/Form1.cs +++ b/Form1.cs @@ -1,350 +1,353 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; -using System.Xml; -using Newtonsoft.Json; -using Microsoft.WindowsAPICodePack.Dialogs; - -namespace MD5Create -{ - public partial class MD5Create : Form - { - public MD5Create() - { - InitializeComponent(); - // Initialize progress bar - progressBar1.Minimum = 0; - progressBar1.Maximum = 100; - progressBar1.Value = 0; - progressBar1.Step = 1; - } - - // 程序启动前检查目录和版本号 - private async void Start_Button_Click(object sender, EventArgs e) - { - if (string.IsNullOrWhiteSpace(Path1_Box.Text)) - { - MessageBox.Show("请先选择目录!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } - - if (string.IsNullOrWhiteSpace(textBox1.Text)) - { - MessageBox.Show("请输入版本号!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } - - // Reset progress bar - progressBar1.Value = 0; - - await Task.Run(() => GenerateMD5Json(Path1_Box.Text)); - } - - private void Choose1_Button_Click(object sender, EventArgs e) - { - // 使用 Windows API Code Pack 中的 CommonOpenFileDialog,开启文件夹选择模式 - using (var dialog = new CommonOpenFileDialog()) - { - dialog.Title = "请选择文件夹"; - dialog.IsFolderPicker = true; // 文件夹选择模式 - dialog.AllowNonFileSystemItems = false; - - if (!string.IsNullOrWhiteSpace(Path1_Box.Text) && Directory.Exists(Path1_Box.Text)) - { - dialog.InitialDirectory = Path1_Box.Text; // 打开到当前路径 - } - - if (dialog.ShowDialog() == CommonFileDialogResult.Ok) - { - Path1_Box.Text = dialog.FileName; // 选择的文件夹路径 - } - } - } - - private void Exit_Button_Click(object sender, EventArgs e) - { - this.Close(); - } - - // 计算 MD5 的值 - private string MD5Generation(string filePath) - { - using (var md5 = MD5.Create()) - using (var stream = File.OpenRead(filePath)) - { - byte[] hash = md5.ComputeHash(stream); - return BitConverter.ToString(hash).Replace("-", "").ToLower(); - } - } - - // 获取目录中文件总数(用于进度计算) - private int GetTotalFileCount(string directoryPath, string excludeFolder) - { - int count = 0; - try - { - count += Directory.GetFiles(directoryPath).Length; - } - catch (Exception) - { - // 忽略无法访问的目录 - } - - try - { - foreach (var dir in Directory.GetDirectories(directoryPath)) - { - if (dir.Equals(excludeFolder, StringComparison.OrdinalIgnoreCase)) - continue; - - // 跳过符号链接 / Junction - var dirInfo = new DirectoryInfo(dir); - if ((dirInfo.Attributes & FileAttributes.ReparsePoint) != 0) - continue; - - count += GetTotalFileCount(dir, excludeFolder); - } - } - catch (Exception) - { - // 同样忽略 - } - return count; - } - - // 生成目录结构的 json 表示 - private Dictionary GenerateDirectoryJson(string directoryPath, string rootPath, int totalFiles, ref int processedFiles, string excludeFolder, string fileFolder) - { - var filesDict = new Dictionary(StringComparer.OrdinalIgnoreCase); - var dirsDict = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // 处理当前目录文件 - string[] files; - try - { - files = Directory.GetFiles(directoryPath); - } - catch (Exception ex) - { - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($"无法访问目录文件列表 {directoryPath}: {ex.Message}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - files = Array.Empty(); - } - - foreach (var file in files) - { - string fileName = Path.GetFileName(file); - string fileMD5; - try - { - fileMD5 = MD5Generation(file); - } - catch (Exception ex) - { - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($"计算MD5失败 {file}: {ex.Message}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - continue; - } - - filesDict[fileName] = fileMD5; - - try - { - string destPath = Path.Combine(fileFolder, fileMD5); - if (!File.Exists(destPath)) - { - File.Copy(file, destPath, overwrite: false); - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($"已复制: {file} -> {destPath}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - } - } - catch (Exception ex) - { - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($"复制文件失败 {file}: {ex.Message}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - } - - // 更新进度条 - processedFiles++; - int progress = (int)((double)processedFiles / totalFiles * 100); - progressBar1.Invoke((MethodInvoker)(() => - { - progressBar1.Value = Math.Min(progress, progressBar1.Maximum); - })); - - // 显示处理路径 - string relativePath = GetRelativePath(file, rootPath); - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($".\\{relativePath}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - } - - // 递归处理子目录 - string[] subDirs; - try - { - subDirs = Directory.GetDirectories(directoryPath); - } - catch (Exception ex) - { - Process_Box.BeginInvoke((MethodInvoker)(() => - { - Process_Box.AppendText($"无法访问子目录列表 {directoryPath}: {ex.Message}{Environment.NewLine}"); - Process_Box.SelectionStart = Process_Box.Text.Length; - Process_Box.ScrollToCaret(); - })); - subDirs = Array.Empty(); - } - - foreach (var dir in subDirs) - { - if (Path.GetFullPath(dir).Equals(Path.GetFullPath(excludeFolder), StringComparison.OrdinalIgnoreCase)) - continue; - - // 跳过符号链接 / Junction - var dirInfo = new DirectoryInfo(dir); - if ((dirInfo.Attributes & FileAttributes.ReparsePoint) != 0) - continue; - - string dirName = Path.GetFileName(dir); - dirsDict[dirName] = GenerateDirectoryJson(dir, rootPath, totalFiles, ref processedFiles, excludeFolder, fileFolder); - } - - var result = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "files", filesDict }, - { "dirs", dirsDict } - }; - - return result; - } - - // 获取相对路径 - private string GetRelativePath(string fullPath, string basePath) - { - if (!basePath.EndsWith(Path.DirectorySeparatorChar.ToString())) - basePath += Path.DirectorySeparatorChar; - - Uri baseUri = new Uri(basePath); - Uri fullUri = new Uri(fullPath); - return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString() - .Replace('/', Path.DirectorySeparatorChar)); - } - - // 生成 json 文件 - private void GenerateMD5Json(string rootDirectory) - { - if (!Directory.Exists(rootDirectory)) - { - this.Invoke((MethodInvoker)(() => - { - MessageBox.Show("指定的目录不存在!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - })); - return; - } - - try - { - this.Invoke((MethodInvoker)(() => - { - Process_Box.Clear(); - progressBar1.Value = 0; - })); - Application.DoEvents(); - - // 存储MD5值 - string md5FolderPath = Path.Combine(rootDirectory, "MD5"); - Directory.CreateDirectory(md5FolderPath); - // 存储MD5值对应的文件 - string fileFolderPath = Path.Combine(md5FolderPath, "File"); - Directory.CreateDirectory(fileFolderPath); - - int totalFiles = GetTotalFileCount(rootDirectory, md5FolderPath); - int processedFiles = 0; - - // 如果文件数量为0,直接设置进度为100% - if (totalFiles == 0) - { - progressBar1.Value = 100; - Process_Box.AppendText("没有找到任何文件\n"); - return; - } - - var directoryStructure = GenerateDirectoryJson(rootDirectory, rootDirectory, totalFiles, ref processedFiles, md5FolderPath, fileFolderPath); - - // 创建包含版本号的新结构 - var versionedStructure = new Dictionary - { - { "version", textBox1.Text.Trim() }, - { "data", directoryStructure } - }; - - // 序列化和保存JSON - string json = JsonConvert.SerializeObject(versionedStructure, Newtonsoft.Json.Formatting.Indented); - string jsonMD5 = CalculateMD5FromString(json); - string outputPath = Path.Combine(md5FolderPath, "md5.json"); - File.WriteAllText(outputPath, json); - - // 最终更新 - this.Invoke((MethodInvoker)(() => - { - progressBar1.Value = 100; - Process_Box.AppendText($"\nmd5.json文件已生成在:{outputPath}\n"); - Process_Box.AppendText($"JSON内容MD5校验值:{jsonMD5}"); - Process_Box.ScrollToCaret(); - })); - } - catch (Exception ex) - { - this.Invoke((MethodInvoker)(() => - { - MessageBox.Show($"生成JSON文件时出错:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); - })); - } - } - - // 计算字符串的MD5值 - private string CalculateMD5FromString(string input) - { - using (var md5 = MD5.Create()) - { - byte[] inputBytes = Encoding.UTF8.GetBytes(input); - byte[] hashBytes = md5.ComputeHash(inputBytes); - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < hashBytes.Length; i++) - { - sb.Append(hashBytes[i].ToString("x2")); // 使用小写十六进制格式 - } - return sb.ToString(); - } - } - } +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml; +using Newtonsoft.Json; +using Microsoft.WindowsAPICodePack.Dialogs; + +namespace MD5Create +{ + public partial class MD5Create : Form + { + public MD5Create() + { + InitializeComponent(); + // 固定窗口启动位置为屏幕左上角 + this.StartPosition = FormStartPosition.Manual; + this.Location = new Point(200, 200); + // Initialize progress bar + progressBar1.Minimum = 0; + progressBar1.Maximum = 100; + progressBar1.Value = 0; + progressBar1.Step = 1; + } + + // 程序启动前检查目录和版本号 + private async void Start_Button_Click(object sender, EventArgs e) + { + if (string.IsNullOrWhiteSpace(Path1_Box.Text)) + { + MessageBox.Show("请先选择目录!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + if (string.IsNullOrWhiteSpace(textBox1.Text)) + { + MessageBox.Show("请输入版本号!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + // Reset progress bar + progressBar1.Value = 0; + + await Task.Run(() => GenerateMD5Json(Path1_Box.Text)); + } + + private void Choose1_Button_Click(object sender, EventArgs e) + { + // 使用 Windows API Code Pack 中的 CommonOpenFileDialog,开启文件夹选择模式 + using (var dialog = new CommonOpenFileDialog()) + { + dialog.Title = "请选择文件夹"; + dialog.IsFolderPicker = true; // 文件夹选择模式 + dialog.AllowNonFileSystemItems = false; + + if (!string.IsNullOrWhiteSpace(Path1_Box.Text) && Directory.Exists(Path1_Box.Text)) + { + dialog.InitialDirectory = Path1_Box.Text; // 打开到当前路径 + } + + if (dialog.ShowDialog() == CommonFileDialogResult.Ok) + { + Path1_Box.Text = dialog.FileName; // 选择的文件夹路径 + } + } + } + + private void Exit_Button_Click(object sender, EventArgs e) + { + this.Close(); + } + + // 计算 MD5 的值 + private string MD5Generation(string filePath) + { + using (var md5 = MD5.Create()) + using (var stream = File.OpenRead(filePath)) + { + byte[] hash = md5.ComputeHash(stream); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } + } + + // 获取目录中文件总数(用于进度计算) + private int GetTotalFileCount(string directoryPath, string excludeFolder) + { + int count = 0; + try + { + count += Directory.GetFiles(directoryPath).Length; + } + catch (Exception) + { + // 忽略无法访问的目录 + } + + try + { + foreach (var dir in Directory.GetDirectories(directoryPath)) + { + if (dir.Equals(excludeFolder, StringComparison.OrdinalIgnoreCase)) + continue; + + // 跳过符号链接 / Junction + var dirInfo = new DirectoryInfo(dir); + if ((dirInfo.Attributes & FileAttributes.ReparsePoint) != 0) + continue; + + count += GetTotalFileCount(dir, excludeFolder); + } + } + catch (Exception) + { + // 同样忽略 + } + return count; + } + + // 生成目录结构的 json 表示 + private Dictionary GenerateDirectoryJson(string directoryPath, string rootPath, int totalFiles, ref int processedFiles, string excludeFolder, string fileFolder) + { + var filesDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + var dirsDict = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // 处理当前目录文件 + string[] files; + try + { + files = Directory.GetFiles(directoryPath); + } + catch (Exception ex) + { + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($"无法访问目录文件列表 {directoryPath}: {ex.Message}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + files = Array.Empty(); + } + + foreach (var file in files) + { + string fileName = Path.GetFileName(file); + string fileMD5; + try + { + fileMD5 = MD5Generation(file); + } + catch (Exception ex) + { + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($"计算MD5失败 {file}: {ex.Message}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + continue; + } + + filesDict[fileName] = fileMD5; + + try + { + string destPath = Path.Combine(fileFolder, fileMD5); + if (!File.Exists(destPath)) + { + File.Copy(file, destPath, overwrite: false); + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($"已复制: {file} -> {destPath}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + } + } + catch (Exception ex) + { + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($"复制文件失败 {file}: {ex.Message}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + } + + // 更新进度条 + processedFiles++; + int progress = (int)((double)processedFiles / totalFiles * 100); + progressBar1.Invoke((MethodInvoker)(() => + { + progressBar1.Value = Math.Min(progress, progressBar1.Maximum); + })); + + // 显示处理路径 + string relativePath = GetRelativePath(file, rootPath); + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($".\\{relativePath}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + } + + // 递归处理子目录 + string[] subDirs; + try + { + subDirs = Directory.GetDirectories(directoryPath); + } + catch (Exception ex) + { + Process_Box.BeginInvoke((MethodInvoker)(() => + { + Process_Box.AppendText($"无法访问子目录列表 {directoryPath}: {ex.Message}{Environment.NewLine}"); + Process_Box.SelectionStart = Process_Box.Text.Length; + Process_Box.ScrollToCaret(); + })); + subDirs = Array.Empty(); + } + + foreach (var dir in subDirs) + { + if (Path.GetFullPath(dir).Equals(Path.GetFullPath(excludeFolder), StringComparison.OrdinalIgnoreCase)) + continue; + + // 跳过符号链接 / Junction + var dirInfo = new DirectoryInfo(dir); + if ((dirInfo.Attributes & FileAttributes.ReparsePoint) != 0) + continue; + + string dirName = Path.GetFileName(dir); + dirsDict[dirName] = GenerateDirectoryJson(dir, rootPath, totalFiles, ref processedFiles, excludeFolder, fileFolder); + } + + var result = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "files", filesDict }, + { "dirs", dirsDict } + }; + + return result; + } + + // 获取相对路径 + private string GetRelativePath(string fullPath, string basePath) + { + if (!basePath.EndsWith(Path.DirectorySeparatorChar.ToString())) + basePath += Path.DirectorySeparatorChar; + + Uri baseUri = new Uri(basePath); + Uri fullUri = new Uri(fullPath); + return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fullUri).ToString() + .Replace('/', Path.DirectorySeparatorChar)); + } + + // 生成 json 文件 + private void GenerateMD5Json(string rootDirectory) + { + if (!Directory.Exists(rootDirectory)) + { + this.Invoke((MethodInvoker)(() => + { + MessageBox.Show("指定的目录不存在!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + })); + return; + } + + try + { + this.Invoke((MethodInvoker)(() => + { + Process_Box.Clear(); + progressBar1.Value = 0; + })); + Application.DoEvents(); + + // 存储MD5值 + string md5FolderPath = Path.Combine(rootDirectory, "MD5"); + Directory.CreateDirectory(md5FolderPath); + // 存储MD5值对应的文件 + string fileFolderPath = Path.Combine(md5FolderPath, "File"); + Directory.CreateDirectory(fileFolderPath); + + int totalFiles = GetTotalFileCount(rootDirectory, md5FolderPath); + int processedFiles = 0; + + // 如果文件数量为0,直接设置进度为100% + if (totalFiles == 0) + { + progressBar1.Value = 100; + Process_Box.AppendText("没有找到任何文件\n"); + return; + } + + var directoryStructure = GenerateDirectoryJson(rootDirectory, rootDirectory, totalFiles, ref processedFiles, md5FolderPath, fileFolderPath); + + // 创建包含版本号的新结构 + var versionedStructure = new Dictionary + { + { "version", textBox1.Text.Trim() }, + { "data", directoryStructure } + }; + + // 序列化和保存JSON + string json = JsonConvert.SerializeObject(versionedStructure, Newtonsoft.Json.Formatting.Indented); + string jsonMD5 = CalculateMD5FromString(json); + string outputPath = Path.Combine(md5FolderPath, "md5.json"); + File.WriteAllText(outputPath, json); + + // 最终更新 + this.Invoke((MethodInvoker)(() => + { + progressBar1.Value = 100; + Process_Box.AppendText($"\nmd5.json文件已生成在:{outputPath}\n"); + Process_Box.AppendText($"JSON内容MD5校验值:{jsonMD5}"); + Process_Box.ScrollToCaret(); + })); + } + catch (Exception ex) + { + this.Invoke((MethodInvoker)(() => + { + MessageBox.Show($"生成JSON文件时出错:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + })); + } + } + + // 计算字符串的MD5值 + private string CalculateMD5FromString(string input) + { + using (var md5 = MD5.Create()) + { + byte[] inputBytes = Encoding.UTF8.GetBytes(input); + byte[] hashBytes = md5.ComputeHash(inputBytes); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hashBytes.Length; i++) + { + sb.Append(hashBytes[i].ToString("x2")); // 使用小写十六进制格式 + } + return sb.ToString(); + } + } + } } \ No newline at end of file