本文介绍了尝试循环此哈希函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我更新的代码,但按下按钮仍然一次生成一个,并且不会自动生成所有代码。代码已更新。 private void openToolStripMenuItem_Click( object sender,EventArgs e) { if (dlgDirectoryBrowser.ShowDialog()== DialogResult.OK) { ImageList smallImageArray = new ImageList(); int smallImageArray_Index = 0 ; listDetailedResults.SmallImageList = smallImageArray; try { listDetailedResults.Items.Clear(); string [] fileEntriesFromDirectoryBrowser = System.IO.Directory.GetFiles(dlgDirectoryBrowser.SelectedPath); foreach ( string fileEntry in fileEntriesFromDirectoryBrowser) { Properties.Settings.Default.fileSizeBeforeConversion = new System.IO.FileInfo(fileEntry).Length; 图标fileEntryIcon = Icon.ExtractAssociatedIcon(fileEntry); smallImageArray.Images.Add(fileEntryIcon); listDetailedResults.Items.Add(System.IO.Path.GetFileName(fileEntry).ToLower(),smallImageArray_Index); listDetailedResults.Items [smallImageArray_Index] .SubItems.Add(GetSizeReadable(Properties.Settings.Default.fileSizeBeforeConversion)); smallImageArray_Index ++; } foreach (ColumnHeader columns in listDetailedResults.Columns) columns.Width = -2; } catch (Exception ex){} Properties.Settings.Default.count = 0 ; Properties.Settings.Default.Save(); } } public static string GetSizeReadable( long i) { string sign =(i < 0 ? - : ); double readable =(i < 0 ?-i:i); string 后缀; if (i > = 0x40000000) // 技嘉 { suffix = GB; readable =( double )(i>> 20 ); } else if (i > = 0x100000) // Megabyte { suffix = MB; readable =( double )(i>> 10 ); } else if (i > = 0x400) // Kilobyte { suffix = KB; readable =( double )i; } else { return i。 ToString(符号+ 0 B); // 字节 } 可读=可读/ 1024 ; 返回符号+ readable.ToString( 0。##)+后缀; } private void bgw_Md5_DoWork( object md5_sender,DoWorkEventArgs md5_e) { byte [] buffer; byte [] oldBuffer; int bytesRead; int oldBytesRead; 长大小; long totalBytesRead = 0 ; 使用(System.IO.Stream stream = System.IO.File.OpenRead(( string )md5_e.Argument)) 使用(System.Security.Cryptography.HashAlgorithm Hash_md5_Algorithm = MD5.Create()) { size = stream.Length; buffer = new byte [ 4096 ]; bytesRead = stream.Read(buffer, 0 ,buffer.Length); totalBytesRead + = bytesRead; do { oldBytesRead = bytesRead; oldBuffer = buffer; buffer = new byte [ 4096 ]; bytesRead = stream.Read(buffer, 0 ,buffer.Length); totalBytesRead + = bytesRead; if (bytesRead == 0 ) { Hash_md5_Algorithm.TransformFinalBlock(oldBuffer, 0 ,oldBytesRead); } else { Hash_md5_Algorithm.TransformBlock(oldBuffer, 0 ,oldBytesRead,oldBuffer, 0 ); } bgWorkerDigest5.ReportProgress(( int )(( double )totalBytesRead * 100 / size)); } while (bytesRead!= 0 ); md5_e.Result = Hash_md5_Algorithm.Hash; } } 私有 void bgw_Md5_RunWorkerCompleted( object md5_sender,RunWorkerCompletedEventArgs md5_e) { StringBuilder sb; sb = new StringBuilder(); // pbBar.Visible = false; foreach ( byte b in ( byte [])md5_e.Result) { sb.AppendFormat( {0:X2},b); } ListViewItem update_lvi = listDetailedResults.Items [Properties.Settings.Default.count]; update_lvi.SubItems.Add(sb.ToString()。ToLower()); // 调整每个Listview项目的列数 foreach (ColumnHeader columns in listDetailedResults.Columns) columns.Width = -2; listDetailedResults.Enabled = true ; listDetailedResults.Focus(); Properties.Settings.Default.count ++; } private void startToolStripMenuItem_Click( object sender,EventArgs e) { foreach (ListViewItem item in listDetailedResults.Items) { if (!bgWorkerDigest5.IsBusy) bgWorkerDigest5 .RunWorkerAsync(dlgDirectoryBrowser.SelectedPath + \\ + item.Text); } } 解决方案 引用:按下按钮仍然一次生成一个并且不会自动生成所有这些 结果并不令人惊讶。第一次循环,你告诉 BackgroundWorker 开始处理后台线程。这项工作比从列表中检索下一个项目花费的时间更长,因此对于循环的所有后续迭代, IsBusy 属性返回 true ,工作永远不会排队。 最简单的解决方案可能是跟踪您正在处理的项目的索引,并排队下一个项目在 RunWorkerCompleted 事件中: private int _currentIndex; private void ProcessItem( int index) { if ( 0 > index || index > = listDetailedResults.Items.Count) { listDetailedResults .Enabled = true ; listDetailedResults.Focus(); } else { _currentIndex = index; listDetailedResults.Enabled = false ; bgWorkerDigest5.RunWorkerAsync(Path.Combine(dlgDirectoryBrowser.SelectedPath,listDetailedResults.Items [index] .Text)); } } private void startToolStripMenuItem_Click( object sender,EventArgs e) { if (!bgWorkerDigest5.IsBusy) { ProcessItem( 0 ); } else { bgWorkerDigest5.CancelAsync(); } } 私有 void bgw_Md5_RunWorkerCompleted( object sender,RunWorkerCompletedEventArgs e) { // 如果用户取消,请停止该过程: 如果(e.Cancelled) { listDetailedResults.Enabled = true ; listDetailedResults.Focus(); return ; } // 如果出现错误,请显示并停止: if (e.Error!= null ) { MessageBox.Show(e.Error.ToString(), 错误,MessageBoxButtons。好的,MessageBoxIcon.Error); listDetailedResults.Enabled = true ; listDetailedResults.Focus(); return ; } // 显示结果: StringBuilder sb = new StringBuilder(); foreach ( byte b in ( byte [])e.Result) { sb.AppendFormat( {0:x2},b); } int index = _currentIndex; ListViewItem lvi = listDetailedResults.Items [index]; lvi.SubItems.Add(sb.ToString()); // 调整每个Listview项目的列数 foreach (ColumnHeader columns in listDetailedResults.Columns) { columns.Width = -2 ; } // 处理下一项: ProcessItem(index + 1 ); } private void bgw_Md5_DoWork( object sender,DoWorkEventArgs e) { using (Stream stream = File.OpenRead(( string )e.Argument)) 使用(HashAlgorithm md5 = MD5.Create()) { // StackOverflow的简化代码: // http://stackoverflow.com/a/3621316/124386 long size = stream.Length; byte [] buffer = new byte [ 4096 ]; long totalBytesRead = 0 ; int bytesRead; while ((bytesRead = stream.Read(buffer, 0 ,缓冲区.Length))!= 0 ) { totalBytesRead + = bytesRead; md5.TransformBlock(buffer, 0 ,bytesRead, null , 0 ); bgWorkerDigest5.ReportProgress(( int )(( double )totalBytesRead * 100 / size)); // 如果用户想取消,则纾困: if (bgWorkerDigest5.CancellationPending) { e.Cancel = true ; return ; } } md5.TransformFinalBlock( new byte [ 0 ], 0 , 0 ); e.Result = md5.Hash; } if (bgWorkerDigest5.CancellationPending) { e.Cancel = 真; } } 我发现只有一种方法的哈希计算 bgw_Md5_DoWork ;并没有显示它是如何调用的。实现建议您在单独的非UI线程中调用它。即使显示了一些循环,也只有一个对象接收散列值, md5_e.Result 。即使它不在循环之外,它也只是一个。我不知道所有这些是什么意思,但你不是要计算多个哈希值。如果您需要多个哈希值,则需要一些集合作为多个哈希值的接收器。由于单个散列值是字节数组, byte [] ,持有多个散列值的数据的数据类型应该是字节数组或数组的某些数组的集合字节数组,这不太合适,因为您可能事先不知道值的总数。这只是你必须做的一件事。 现在,让我们看一下你在循环中调用的两种方法。即使你的代码没有全面地代表问题,它也不太可能只是 System.Security.Cryptography.TransformBlock 和 System.Security .Cryptography.TransformFinalBlock : https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx [ ^ ], https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx [ ^ ]。 第一种方法将数据放在输出缓冲区中,最后一种方法只返回字节数组。您的缓冲区是局部变量,因此您不会在方法返回时保留您在输出缓冲区中收集的任何数据。至于第二种方法,你只需忽略它的返回。难怪你丢失了哈希数据。因此,如果您需要此数据,则不应忽略返回,并且需要将其保存在此函数之外创建的某些数据集合对象中;你需要将集合引用传递给你的方法。 另外,如果你真的使用非UI线程进行操作,你可能会有一些困难将数据传入以及我们在此线程中调用的方法数据。为此,请查看我建议并广泛使用的线程包装器技术。在我过去的答案中解释了一切: 更改线程(生产者)启动后的参数 [ ^ ], 如何将ref参数传递给线程 [ ^ ], 列表更新中的类在他们自己的线程中 [ ^ ], AsyncCallback and Threadings [ ^ ](完全可操作的样本), C#中的MultiThreading [ ^ ]。 -SA My updated code, however pressing the button still generates one at a time and does not generate all of them automatically. Code updated.private void openToolStripMenuItem_Click(object sender, EventArgs e) { if (dlgDirectoryBrowser.ShowDialog() == DialogResult.OK) { ImageList smallImageArray = new ImageList(); int smallImageArray_Index = 0; listDetailedResults.SmallImageList = smallImageArray; try { listDetailedResults.Items.Clear(); string[] fileEntriesFromDirectoryBrowser = System.IO.Directory.GetFiles(dlgDirectoryBrowser.SelectedPath); foreach (string fileEntry in fileEntriesFromDirectoryBrowser) { Properties.Settings.Default.fileSizeBeforeConversion = new System.IO.FileInfo(fileEntry).Length; Icon fileEntryIcon = Icon.ExtractAssociatedIcon(fileEntry); smallImageArray.Images.Add(fileEntryIcon); listDetailedResults.Items.Add(System.IO.Path.GetFileName(fileEntry).ToLower(), smallImageArray_Index); listDetailedResults.Items[smallImageArray_Index].SubItems.Add(GetSizeReadable(Properties.Settings.Default.fileSizeBeforeConversion)); smallImageArray_Index++; } foreach (ColumnHeader columns in listDetailedResults.Columns) columns.Width = -2; } catch (Exception ex) { } Properties.Settings.Default.count = 0; Properties.Settings.Default.Save(); } } public static string GetSizeReadable(long i) { string sign = (i < 0 ? "-" : ""); double readable = (i < 0 ? -i : i); string suffix; if (i >= 0x40000000) // Gigabyte { suffix = "GB"; readable = (double)(i >> 20); } else if (i >= 0x100000) // Megabyte { suffix = "MB"; readable = (double)(i >> 10); } else if (i >= 0x400) // Kilobyte { suffix = "KB"; readable = (double)i; } else { return i.ToString(sign + "0 B"); // Byte } readable = readable / 1024; return sign + readable.ToString("0.## ") + suffix; } private void bgw_Md5_DoWork(object md5_sender, DoWorkEventArgs md5_e) { byte[] buffer; byte[] oldBuffer; int bytesRead; int oldBytesRead; long size; long totalBytesRead = 0; using (System.IO.Stream stream = System.IO.File.OpenRead((string)md5_e.Argument)) using (System.Security.Cryptography.HashAlgorithm Hash_md5_Algorithm = MD5.Create()) { size = stream.Length; buffer = new byte[4096]; bytesRead = stream.Read(buffer, 0, buffer.Length); totalBytesRead += bytesRead; do { oldBytesRead = bytesRead; oldBuffer = buffer; buffer = new byte[4096]; bytesRead = stream.Read(buffer, 0, buffer.Length); totalBytesRead += bytesRead; if (bytesRead == 0) { Hash_md5_Algorithm.TransformFinalBlock(oldBuffer, 0, oldBytesRead); } else { Hash_md5_Algorithm.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0); } bgWorkerDigest5.ReportProgress((int)((double)totalBytesRead * 100 / size)); } while (bytesRead != 0); md5_e.Result = Hash_md5_Algorithm.Hash; } } private void bgw_Md5_RunWorkerCompleted(object md5_sender, RunWorkerCompletedEventArgs md5_e) { StringBuilder sb; sb = new StringBuilder(); //pbBar.Visible = false; foreach (byte b in (byte[])md5_e.Result) { sb.AppendFormat("{0:X2}", b); } ListViewItem update_lvi = listDetailedResults.Items[Properties.Settings.Default.count]; update_lvi.SubItems.Add(sb.ToString().ToLower()); //Resize Columns For Each Listview Item foreach (ColumnHeader columns in listDetailedResults.Columns) columns.Width = -2; listDetailedResults.Enabled = true; listDetailedResults.Focus(); Properties.Settings.Default.count++; } private void startToolStripMenuItem_Click(object sender, EventArgs e) { foreach (ListViewItem item in listDetailedResults.Items) { if (!bgWorkerDigest5.IsBusy) bgWorkerDigest5.RunWorkerAsync(dlgDirectoryBrowser.SelectedPath + "\\" + item.Text); } } 解决方案 Quote:pressing the button still generates one at a time and does not generate all of them automaticallyThe result is hardly surprising. The first time through the loop, you tell the BackgroundWorker to start working on a background thread. The work takes longer than retrieving the next item from the list, so for all subsequent iterations of your loop, the IsBusy property returns true, and the work is never queued.The simplest solution is probably to track the index of the item you're processing, and queue up the next item in the RunWorkerCompleted event:private int _currentIndex;private void ProcessItem(int index){ if (0 > index || index >= listDetailedResults.Items.Count) { listDetailedResults.Enabled = true; listDetailedResults.Focus(); } else { _currentIndex = index; listDetailedResults.Enabled = false; bgWorkerDigest5.RunWorkerAsync(Path.Combine(dlgDirectoryBrowser.SelectedPath, listDetailedResults.Items[index].Text)); }}private void startToolStripMenuItem_Click(object sender, EventArgs e){ if (!bgWorkerDigest5.IsBusy) { ProcessItem(0); } else { bgWorkerDigest5.CancelAsync(); }}private void bgw_Md5_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){ // If the user cancelled, stop the process: if (e.Cancelled) { listDetailedResults.Enabled = true; listDetailedResults.Focus(); return; } // If there was an error, display it and stop: if (e.Error != null) { MessageBox.Show(e.Error.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); listDetailedResults.Enabled = true; listDetailedResults.Focus(); return; } // Display the result: StringBuilder sb = new StringBuilder(); foreach (byte b in (byte[])e.Result) { sb.AppendFormat("{0:x2}", b); } int index = _currentIndex; ListViewItem lvi = listDetailedResults.Items[index]; lvi.SubItems.Add(sb.ToString()); //Resize Columns For Each Listview Item foreach (ColumnHeader columns in listDetailedResults.Columns) { columns.Width = -2; } // Process the next item: ProcessItem(index + 1);}private void bgw_Md5_DoWork(object sender, DoWorkEventArgs e){ using (Stream stream = File.OpenRead((string)e.Argument)) using (HashAlgorithm md5 = MD5.Create()) { // Simplified code from StackOverflow: // http://stackoverflow.com/a/3621316/124386 long size = stream.Length; byte[] buffer = new byte[4096]; long totalBytesRead = 0; int bytesRead; while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0) { totalBytesRead += bytesRead; md5.TransformBlock(buffer, 0, bytesRead, null, 0); bgWorkerDigest5.ReportProgress((int)((double)totalBytesRead * 100 / size)); // If the user wants to cancel, then bail out: if (bgWorkerDigest5.CancellationPending) { e.Cancel = true; return; } } md5.TransformFinalBlock(new byte[0], 0, 0); e.Result = md5.Hash; } if (bgWorkerDigest5.CancellationPending) { e.Cancel = true; }}I've found hash calculation only in one method bgw_Md5_DoWork; and it's not shown how it's called. The implementation suggests that you call it in a separate non-UI thread. Even though some loop is shown, there is only one object which receives the hash value, md5_e.Result. Even if it wasn't outside of the loop, it would be only one. I don't know what do you mean by "all of them", but you are not trying to calculate more than one hash value. If you need more than one hash value, you need some collection which works as a sink for multiple hash values. As a single hash value is array of bytes, byte [], the data type for the data holding several hash value should be some collection of arrays of arrays of bytes, or array of array of bytes, which would be less suitable, because you may not know total number of values in advance. This is just one thing you have to do.Now, let's look at two methods you call in the loop. Even though your code does not comprehensively represent the problem, it's very unlikely that it can be anything but System.Security.Cryptography.TransformBlock and System.Security.Cryptography.TransformFinalBlock:https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx[^],https://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.transformblock%28v=vs.110%29.aspx[^].First method places data in output buffer, and the last one simply returns array of bytes. Your buffers are local variables, so you don't keep any data you would collect in output buffer on the method return. As to the second method, you simply ignore its return. No wonder you loose the hash data. So, if you need this data, you should not ignore the return, and need to save it in some data collection(s) object(s) created outside of this function; you will need to pass the collection reference to your method.Also, if you really use non-UI thread for the operation, you may have some difficulty passing data into and our of the data of your methods called in this thread. For this purpose, look at my thread wrapper technique I've suggested and widely use. Everything is explained in my past answers:Change parameters of thread (producer) after it is started[^],How to pass ref parameter to the thread[^],Classes in list updating in their own thread[^],AsyncCallback and Threadings[^] (with fully operational sample),MultiThreading in C#[^].—SA 这篇关于尝试循环此哈希函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 09-27 05:16