Search code examples
c#filestreamcryptostream

CryptoStream ReportProgress ProgressBar C#


So I am trying to encrypt some files and it works fine, but when I try to include a progress bar to show how far along big files are, like a 100mb-1gb file, the performance is slashed and is very slow. I am assuming its because ReportProgress was being called to quickly, so I added in a stopwatch to only update every 2 seconds, but that caused it to work much faster (still not as fast without calling reportProgress) but also sometimes not update the progress bar at all.

using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
            {
                using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
                    {
                        int data;
                        int test = 0;
                        Stopwatch stopw = new Stopwatch();
                        stopw.Start();
                        while ((data = fsIn.ReadByte()) != -1)
                        {
                            cs.WriteByte((byte) data);
                            test++;
                            if (stopw.Elapsed.Seconds > 2)
                            {
                                stopw.Reset();
                                backgroundWorker1.ReportProgress((int) fsIn.Length);

                            }
                        }
                        stopw.Stop();
                    }
                }
            }

An example is that with the backgroundWorker1.ReportProgress((int) fsIn.Length); line removed a file can take 5 seconds, but with it added in, it ends up taking 20 seconds.

What can I do to improve this and make it faster?


Solution

  • My suggestion is to not use stopwatch but just go on the # of bytes. Maybe checking the stopwatch elapsed after every byte is taking a long time (seems unlikely though but who knows). Also, get fsIn.Length one time outside of the while loop.

    using (FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create))
    {
        using (CryptoStream cs = new CryptoStream(fsCrypt, AES.CreateEncryptor(), CryptoStreamMode.Write))
        {
            using (FileStream fsIn = new FileStream(inputFile, FileMode.Open))
            {
                int data;
                long test = 0;
                long total = fsIn.Length;
                while ((data = fsIn.ReadByte()) != -1)
                {
                    cs.WriteByte((byte) data);
                    test++;
                    if (test % 10000 == 0)
                    {
                        backgroundWorker1.ReportProgress((int) (test * 100 / total));
    
                    }
                }
            }
        }
    }
    

    Also make sure the code in your ReportProgress event handler is not the culprit. You don't want to do anything expensive in there.