我正在尝试在C#中多线程AES,但我似乎无法解决这个奇怪的异常。我的缓冲区大小完全相同,但它仍然表示无法扩展,也许你可以看到错误,这是一个大小为101字节的文件。
在while循环中,它将跳过if并进入else创建(一个线程?),将未加密的缓冲区写入加密缓冲区。在完成同步之后,我想将加密缓冲区写入runworkerComplete函数中的文件。当我尝试将未加密的缓冲区写入加密缓冲区时,问题出现了。错误信息让我感到困惑,因为第二个缓冲区的大小是用第一个缓冲区的长度创建的,但是说它不能扩展内存!?
static List<BackgroundWorker> threadCompany = new List<BackgroundWorker>();
static List<BackgroundWorker> listWorkers = new List<BackgroundWorker>();
static List<BackgroundWorker> listFreeWorkers = new List<BackgroundWorker>();
static FileStream fsIn;
static string file;
static byte[] key;
const int BLOCK_SIZE = 1000;
static FileStream outFile;
public static void EncryptFile(string inputFile, string outputFile, string sKey, ProgressBar progress)
{
String fileName = inputFile;
fileName = "\\" + fileName.Split('\\').Last();
var progres = new Progress<int>(value => progress.Value = value);
file = outputFile + fileName;
fsIn = new FileStream(inputFile, FileMode.Open);
outFile = new FileStream(file, FileMode.Create);
key = new UnicodeEncoding().GetBytes(sKey);
for (int t = 0; t < 4; t++)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
listWorkers.Add(worker);
listFreeWorkers.Add(worker);
}
byte[] buffer = new byte[BLOCK_SIZE];
FileInfo fileInfo = new FileInfo(inputFile);
double numBlocks = Math.Ceiling(((double)fileInfo.Length) / BLOCK_SIZE);
int ixCurrentBlock = 0;
while (ixCurrentBlock < numBlocks)
{
//check if any free workers
if (listFreeWorkers.Count > 0)
{
//Get the worker, remove it from the list
BackgroundWorker freeWorker = listFreeWorkers[0];
listFreeWorkers.RemoveAt(0);
//read the next block of the file
int bytes;
if (ixCurrentBlock < numBlocks - 1)
{
bytes = fsIn.Read(buffer, ixCurrentBlock * BLOCK_SIZE, BLOCK_SIZE);
freeWorker.RunWorkerAsync(Tuple.Create(ixCurrentBlock, buffer));
threadCompany.Remove(freeWorker);
}
else //special handling for last block
{
MessageBox.Show((ixCurrentBlock * BLOCK_SIZE) + " " + (int)(fileInfo.Length - ixCurrentBlock * BLOCK_SIZE)); // 0 101
bytes = fsIn.Read(buffer, ixCurrentBlock * BLOCK_SIZE, (int)(fileInfo.Length - ixCurrentBlock * BLOCK_SIZE));
freeWorker.RunWorkerAsync(Tuple.Create(ixCurrentBlock, new byte[(int)(fileInfo.Length - ixCurrentBlock * BLOCK_SIZE)]));
threadCompany.Remove(freeWorker);
}
//now pass it to a worker
//advance to the next block
ixCurrentBlock++;
//update the UI status here
// ...
}
else //no workers free
{
Thread.Sleep(50);
}
}
//if we make it to here we have sent off all the blocks
//now we wait for the threads to complete
bool threadsRunning = false;
while (threadsRunning)
{
threadsRunning = false;
foreach (BackgroundWorker worker in listWorkers)
{
threadsRunning |= worker.IsBusy;
}
//if still running, wait and try again in 50ms
if (threadsRunning)
{
Thread.Sleep(50);
}
}
}
private static void worker_DoWork(object sender, DoWorkEventArgs e)
{
Tuple<int, byte[]> t = e.Argument as Tuple<int, byte[]>;
int blockIndex = (int)t.Item1;
byte[] inBuffer = (byte[])t.Item2;
byte[] outBuffer = new byte[inBuffer.Length];
//using keyword will automatically close the stream
using (MemoryStream outStream = new MemoryStream(outBuffer)) // issue may be here?
{
RijndaelManaged RMCrypto = new RijndaelManaged();
using (CryptoStream cs = new CryptoStream(outStream,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write))
{
// I want to write inbuffer non encrypted to outbuffer encrypted.
cs.Write(inBuffer, blockIndex, inBuffer.Length);
}
}
e.Result = Tuple.Create(blockIndex, outBuffer);
}
private static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show(e.Error.Message + " "); // memory is not expendable
Tuple<int, byte[]> t = e.Result as Tuple<int, byte[]>;
int blockIndex = (int)t.Item1;
byte[] buffer = (byte[])t.Item2;
//assumes you have a class variable, _outFile, that is an open filestream
outFile.Write(buffer, blockIndex, buffer.Length);
outFile.Close();
//add the worker back to the free workers list
listFreeWorkers.Add((BackgroundWorker)sender);
}
答案 0 :(得分:2)
Encryption and decryption arn't the same size to solve this issue flush the stream (already implied with the using
statement) toarray the stream to your outbuffer.
SOLUTION
private static void worker_DoWork(object sender, DoWorkEventArgs e)
{
Tuple<int, byte[]> t = e.Argument as Tuple<int, byte[]>;
int blockIndex = (int)t.Item1;
byte[] inBuffer = (byte[])t.Item2;
byte[] outBuffer;
//using keyword will automatically close the stream
using (MemoryStream outStream = new MemoryStream()) // issue may be here?
{
AesCryptoServiceProvider RMCrypto = new AesCryptoServiceProvider();
using (CryptoStream cs = new CryptoStream(outStream,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write))
{
// I want to write inbuffer non encrypted to outbuffer encrypted.
cs.Write(inBuffer, blockIndex, inBuffer.Length);
}
outBuffer = outStream.ToArray();
}
e.Result = Tuple.Create(blockIndex, outBuffer);
}