If you could not use .Net 4.5, I would suggest you use one stream for reading from disk, one stream for encryption, and one stream for downloading. To communicate between them, you must use the producer-consumer pattern in the form of a BlockingCollection<byte[]> between each pair of threads (1-2 and 2-3).
But since you can use .Net 4.5, you can use TPL Dataflow, which is ideal for this task. Using TPL Dataflow means that you wonβt spend threads reading and loading (although this most likely doesnβt matter much to you). More importantly, this means that you can easily parallelize the encryption of each fragment (if you can).
What would you do is have one block for encryption, one block for download, and one asynchronous task (in fact, it should not be a complete Task ) to read from a file. The block for encryption can be configured to run in parallel, and both blocks must be configured with maximum throughput (otherwise, throttling will not work correctly and the entire file will be read as quickly as possible, which can lead to an OutOfMemoryException).
In code:
var uploadBlock = new ActionBlock<byte[]>( data => uploadStream.WriteAsync(data, 0, data.Length), new ExecutionDataflowBlockOptions { BoundedCapacity = capacity }); var encryptBlock = new TransformBlock<byte[], byte[]>( data => Encrypt(data), new ExecutionDataflowBlockOptions { BoundedCapacity = capacity, MaxDegreeOfParallelism = degreeOfParallelism }); encryptBlock.LinkTo( uploadBlock, new DataflowLinkOptions { PropagateCompletion = true }); while (true) { byte[] chunk = new byte[chunkSize]; int read = await fileStream.ReadAsync(chunk, 0, chunk.Length); if (read == 0) break; await encryptBlock.SendAsync(chunk); } fileStream.Close(); encryptBlock.Complete(); await uploadBlock.Completion; uploadStream.Close();
svick source share