我正在使用此代码加密/解密文件:
Public Shared Sub encryptordecryptfile(ByVal strinputfile As String, _
ByVal stroutputfile As String, _
ByVal bytkey() As Byte, _
ByVal bytiv() As Byte, _
ByVal direction As CryptoAction)
Try
fsInput = New System.IO.FileStream(strinputfile, FileMode.Open, FileAccess.Read)
fsOutput = New System.IO.FileStream(stroutputfile, FileMode.OpenOrCreate, FileAccess.Write)
fsOutput.SetLength(0)
Dim bytbuffer(4096) As Byte
Dim lngbytesprocessed As Long = 0
Dim lngfilelength As Long = fsInput.Length
Dim intbytesincurrentblock As Integer
Dim cscryptostream As CryptoStream
Dim csprijndael As New System.Security.Cryptography.RijndaelManaged
Select Case direction
Case CryptoAction.ActionEncrypt
cscryptostream = New CryptoStream(fsOutput, _
csprijndael.CreateEncryptor(bytkey, bytiv), _
CryptoStreamMode.Write)
Case CryptoAction.ActionDecrypt
cscryptostream = New CryptoStream(fsOutput, _
csprijndael.CreateDecryptor(bytkey, bytiv), _
CryptoStreamMode.Write)
End Select
While lngbytesprocessed < lngfilelength
intbytesincurrentblock = fsInput.Read(bytbuffer, 0, 4096)
cscryptostream.Write(bytbuffer, 0, intbytesincurrentblock)
lngbytesprocessed = lngbytesprocessed + CLng(intbytesincurrentblock)
End While
cscryptostream.Close()
fsInput.Close()
fsOutput.Close()
Catch ex As Exception
End Try
End Sub
我是否需要将此过程的百分比作为整数来完成。我将使用后台工作程序,因此我需要从后台工作程序调用此子程序,并能够继续刷新后台工作程序报告的进度条。这可能吗? 提前谢谢。
答案 0 :(得分:1)
您可以采取一些措施来提高您的加密效率和其他问题:
encryptordecryptfile
这样的方法,然后需要&#34;模式&#34;知道采取哪种行动的论点意味着它可能会更好地作为2种方法ProgressChanged
个ProgressBar
事件的暴风雪,While
无法跟上动画。一个700K的文件将产生170个左右的微量进度报告值得注意的是,您可以使用fsInput.CopyTo(cscryptostream)
替换整个BackgroundWorker
块,以便一次性处理该文件。但这不允许进度报告。它也没有更快。
您可能希望将其实现为Task
,而不是DoWork
(可以正常工作)。这样做的原因是所有这些变量都需要从点击按钮到实际调用方法的EncryptFile
事件。任务不是使用全局变量或类来保存它们,而是更直接地工作(但在报告进度时确实需要一个额外的步骤)。首先,修改后的Private Sub EncryptFile(inFile As String,
outFile As String,
pass As String,
Optional reporter As ProgressReportDelegate = Nothing)
Const BLOCKSIZE = 4096
Dim percentDone As Integer = 0
Dim totalBytes As Int64 = 0
Dim buffSize As Int32
' Note A
Dim key = GetHashedBytes(pass)
Dim iv = GetRandomBytes(16)
Dim cryptor As ICryptoTransform
' Note B
Using fsIn As New FileStream(inFile, FileMode.Open, FileAccess.Read),
fsOut As New FileStream(outFile, FileMode.OpenOrCreate, FileAccess.Write)
fsOut.SetLength(0)
' Note C
'ToDo: work out optimal block size for Lg vs Sm files
If fsIn.Length > (2 * BLOCKSIZE) Then
' use buffer size to limit to 20 progress reports
buffSize = CInt(fsIn.Length \ 20)
' to multiple of 4096
buffSize = CInt(((buffSize + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE)
' optional, limit to some max size like 256k?
'buffSize = Math.Min(buffSize, BLOCK256K)
Else
buffSize = BLOCKSIZE
End If
Dim buffer(buffSize-1) As Byte
' Note D
' write the IV to "naked" fs
fsOut.Write(iv, 0, iv.Length)
Using rij = Rijndael.Create()
rij.Padding = PaddingMode.ISO10126
Try
cryptor = rij.CreateEncryptor(key, iv)
Using cs As New CryptoStream(fsOut, cryptor, CryptoStreamMode.Write)
Dim bytesRead As Int32
Do Until fsIn.Position = fsIn.Length
bytesRead = fsIn.Read(buffer, 0, buffSize)
cs.Write(buffer, 0, bytesRead)
If reporter IsNot Nothing Then
totalBytes += bytesRead
percentDone = CInt(Math.Floor((totalBytes / fsIn.Length) * 100))
reporter(percentDone)
End If
Loop
End Using
Catch crEx As CryptographicException
' ToDo: Set breakpoint and inspect message
Catch ex As Exception
' ToDo: Set breakpoint and inspect message
End Try
End Using
End Using
End Sub
方法:
Public Shared Function GetHashedBytes(data As String) As Byte()
Dim hBytes As Byte()
' or SHA512Managed
Using hash As HashAlgorithm = New SHA256Managed()
' convert data to bytes:
Dim dBytes = Encoding.UTF8.GetBytes(data)
' hash the result:
hBytes = hash.ComputeHash(dBytes)
End Using
Return hBytes
End Function
Public Shared Function GetRandomBytes(size As Integer) As Byte()
Dim data(size - 1) As Byte
Using rng As New RNGCryptoServiceProvider
' fill the array
rng.GetBytes(data)
End Using
Return data
End Function
注意A
它可以处理的标准加密任务之一是为您创建Key和IV阵列。这些非常简单,可以是共享/静态成员。
Using
稍后将会看到,您可以将IV存储在加密文件中,而不是在代码中保存和管理它。
注B
Dispose
阻止关闭并为您处置资源。基本上,如果某个东西有Using
方法,那么你应该将它包装在Dim t As Task
t = Task.Run(Sub() EncryptFile(inFile, oFile, "MyWeakPassword",
AddressOf ReportProgress))
...
块中。
注意C
您不希望报告每个块读取的进度,这只会压倒ProgressBar。而不是另一个变量来跟踪进度何时改变了一些量,此代码首先创建一个缓冲区大小,该大小为输入文件大小的5%,因此将有大约20个报告(每5%)。
如注释所示,您可能需要添加一些代码来设置最小/最大缓冲区大小。这样做会改变进度报告的频率。
注意D
在将它包装在CryptoStream中之前,您可以将IV()写入文件流(当然,在解密时首先将其读回)。这可以防止您必须存储IV。
最后一部分是将其作为一项任务:
Task
BGW所做的是在一个线程上执行工作,但是在UI线程上报告了进度。作为Invoke
,我们需要做的就是使用Delegate Sub ProgressReportDelegate(value As Int32)
Private Sub ReportProgress(v As Int32)
If progBar.InvokeRequired Then
progBar.Invoke(Sub() progBar.Value = v)
Else
progBar.Value = v
progBar.Invalidate()
End If
End Sub
:
' small file, no progress report:
EncryptFile(ifile, oFile, "MyWeakPassword")
' report progress, but run on UI thread
EncryptFile(ifile, oFile, "MyWeakPassword",
AddressOf ReportProgress)
' run as task
Dim t As Task
t = Task.Run(Sub() EncryptFile(ifile, oFile, "MyWeakPassword",
AddressOf ReportProgress))
加密器可以直接使用,也可以作为任务使用。对于小文件,您可以完全省略进度报告:
SELECT * FROM items ORDER BY tags ASC;
...如果你有一个要做的文件列表,你可以一次性运行它们,也许可以报告总进度。