C# 计算输入和输出 FileStream 的 MD5
Posted
技术标签:
【中文标题】C# 计算输入和输出 FileStream 的 MD5【英文标题】:C# Calculate an MD5 of an Input and Output FileStream 【发布时间】:2022-01-14 15:59:06 【问题描述】:我正在使用 this(稍作修改)从文件共享中复制大文件,如果下载中断,可以继续复制。它在 BackroudWorker 中运行并报告进度。这工作正常,但我希望能够在每次将文件数据块写入磁盘时以最小的额外开销将当前的 MD5 哈希写入磁盘(当前总数,而不是每个块一次)。如果发现部分文件,我想从文件中读取 MD5 哈希,如果它与部分文件相同,则继续复制。当文件被完全复制后,文件中的 MD5 哈希值应该是完全复制文件的 MD5 哈希值。我想稍后用它来确定源文件和目标文件是相同的。感谢您的帮助!
这是我目前的复制方法:
public static bool CopyFile(List<CopyObjects> FileList, FSObjToCopy job, BackgroundWorker BW)
Stopwatch sw = new Stopwatch();
long RestartPosition = 0;
bool Retry = false;
int BYTES_TO_READ = (0x200000)
foreach (CopyObjects co in FileList)
FileInfo fi = co.file;
FileInfo fo = null;
if (fi.Directory.FullName.StartsWith($@"Test_Updater_Core.ServerName\Test_Updater_Core.ServerTemplateRoot"))
if (File.Exists(fi.FullName.Replace($@"Test_Updater_Core.ServerName\Test_Updater_Core.ServerTemplateRoot", $@" Test_Updater_Core.USBStore_Drive.driveInfo.Name.Replace("\\", "")\Test_Updater_Core.UsbTemplateRoot")))
fi = new FileInfo(fi.FullName.Replace($@"Test_Updater_Core.ServerName\Test_Updater_Core.ServerTemplateRoot", $@"Test_Updater_Core.USBStore_Drive.driveInfo.Name.Replace("\\", "")\Test_Updater_Core.UsbTemplateRoot"));
co.destination = co.destination.Replace($@"Test_Updater_Core.USBStore_Drive.driveInfo.Name.Replace("\\", "")\Test_Updater_Core.UsbTemplateRoot", $@"Test_Updater_Core.LocalInstallDrive\Test_Updater_Core.LocalTemplateRoot");
fo = new FileInfo($"fi.FullName.Replace($@"Test_Updater_Core.USBStore_Drive.driveInfo.Name.Replace("\\", "")\Test_Updater_Core.UsbTemplateRoot", $@"Test_Updater_Core.LocalInstallDrive\Test_Updater_Core.LocalTemplateRoot")Test_Updater_Core.TempFileExtension");
//If a clean cancellation was requested, we do it here, otherwise the BackgroundWorker will be killed
if (BW.CancellationPending)
job.Status = FSObjToCopy._Status.Complete;
return false;
//If a pause is requested, we loop here until resume or termination has been signaled
while (job.PauseBackgroundWorker == true)
Thread.Sleep(100);
if (BW.CancellationPending)
job.Status = FSObjToCopy._Status.Complete;
return false;
Application.DoEvents();
if (fo == null)
fo = new FileInfo($"fi.FullName.Replace(job.Source, co.destination)Test_Updater_Core.TempFileExtension");
if (fo.Exists)
Retry = true;
RestartPosition = fo.Length - BYTES_TO_READ;
else
RestartPosition = 0;
Retry = false;
if (RestartPosition <= 0)
Retry = false;
sw.Start();
try
// Read source files into file streams
FileStream source = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read);
// Additional way to write to file stream
FileStream dest = new FileStream(fo.FullName, FileMode.OpenOrCreate, FileAccess.Write);
// Actual read file length
int destLength = 0;
// If the length of each read is less than the length of the source file, read in chunks
if (BYTES_TO_READ < source.Length)
byte[] buffer = new byte[BYTES_TO_READ];
long copied = 0;
if (Retry)
source.Seek(RestartPosition, SeekOrigin.Begin);
dest.Seek(RestartPosition, SeekOrigin.Begin);
Retry = false;
while (copied <= source.Length - BYTES_TO_READ)
destLength = source.Read(buffer, 0, BYTES_TO_READ);
source.Flush();
dest.Write(buffer, 0, BYTES_TO_READ);
dest.Flush();
// Current position of flow
dest.Position = source.Position;
copied += BYTES_TO_READ;
job.CopiedSoFar += BYTES_TO_READ;
if (sw.ElapsedMilliseconds > 250)
job.PercComplete = (int)(float)((float)job.CopiedSoFar / (float)job.TotalFileSize * 100);
sw.Restart();
sw.Start();
job.ProgressCell.Value = job.PercComplete;
BW.ReportProgress(job.PercComplete < 100 ? job.PercComplete : 99);
if (BW.CancellationPending)
job.Status = FSObjToCopy._Status.Complete;
return false;
while (job.PauseBackgroundWorker == true)
Thread.Sleep(100);
if (BW.CancellationPending)
job.Status = FSObjToCopy._Status.Complete;
return false;
Application.DoEvents();
int left = (int)(source.Length - copied);
destLength = source.Read(buffer, 0, left);
source.Flush();
dest.Write(buffer, 0, left);
dest.Flush();
job.CopiedSoFar += left;
else
// If the file length of each copy is longer than that of the source file, the actual file length is copied directly.
byte[] buffer = new byte[source.Length];
source.Read(buffer, 0, buffer.Length);
source.Flush();
dest.Write(buffer, 0, buffer.Length);
dest.Flush();
job.CopiedSoFar += source.Length;
job.PercComplete = (int)(float)((float)job.CopiedSoFar / (float)job.TotalFileSize * 100);
job.ProgressCell.Value = job.PercComplete;
BW.ReportProgress(job.PercComplete < 100 ? job.PercComplete : 99);
source.Close();
dest.Close();
fo.LastWriteTimeUtc = fi.LastWriteTimeUtc;
if (File.Exists(fo.FullName))
if (File.Exists(fo.FullName.Replace($"Test_Updater_Core.TempFileExtension", "")))
File.Delete(fo.FullName.Replace($"Test_Updater_Core.TempFileExtension", ""));
File.Move(fo.FullName, fo.FullName.Replace($"Test_Updater_Core.TempFileExtension", ""));
job.ProgressCell.Value = job.PercComplete;
BW.ReportProgress(job.PercComplete);
catch (Exception ex)
MessageBox.Show($"There was an error copying:Environment.NewLinefiEnvironment.NewLineto:" +
$"Environment.NewLinefoEnvironment.NewLineThe error is: Environment.NewLineex.Message",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
job.Status = FSObjToCopy._Status.Error;
return false;
finally
sw.Stop();
return true;
【问题讨论】:
有一行“md5InFile.TransformBlock(buffer,)”不应该存在。抱歉! BackgoundWorker 类自 2012 年以来已过时,完全被 async/await、Task.Run 和 IProgress我决定在服务器上创建包含一系列校验和的校验和文件。当我复制文件时,我将校验和添加到内部列表中,并将它们与服务器列表进行比较。如果在某些时候,它们不匹配,我会回到它们相同的位置并从那里重新开始。在复制作业结束时,我将内部列表中的校验和写入磁盘,与服务器的名称相同。如果我想检查文件的完整性,我可以将服务器文件与本地文件进行比较并验证校验和。
【讨论】:
以上是关于C# 计算输入和输出 FileStream 的 MD5的主要内容,如果未能解决你的问题,请参考以下文章