By 13aal


2016-05-23 20:53:53 8 Comments

I asked this question on Stackoverflow, and was told I might have better luck here.

I'm new to and have created a basic file archiver. It works, and it does what it's suppose to do, but I think it's pretty slow. I added a simple benchmark in order to test the speed and ran it five times.

  1. 50.7120707 seconds
  2. 46.5686564 seconds
  3. 50.2020197 seconds
  4. 44.8384834 seconds
  5. 44.5264522 seconds

So the average time for this process to run is 47.369536648 seconds. I understand that depending on the size of the files it's archiving and depending on how many files plays a big roll, so here's an image of the file sizes that I'm using as my test:

enter image description here

enter image description here

So the files really aren't to big, so I'm not sure if this is a good process time or not, it seems a little slow to me and I was wondering if there's anyway I can speed this up?

using System;
using System.IO;
using System.IO.Compression;

namespace ArchiveCreator
{
    class Archive
    {

        //These static strings are used for 
        //information handling they will be
        //color coordinated so you can see
        //what kind of information is being 
        //passed to you
        static string Success(string input)
        {
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine(input);
            return input;
        }

        static string Warn(string input)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(input);
            return input;
        }

        static string Say(string input)
        {
            Console.ForegroundColor = ConsoleColor.DarkCyan;
            Console.WriteLine(input);
            return input;
        }

        static string FatalErr(string input)
        {
            Console.ForegroundColor = ConsoleColor.DarkRed;
            Console.WriteLine(input);
            return input;
        }

        static string MinorErr(string input)
        {
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            Console.WriteLine(input);
            return input;
        }

        //Main method
        static void Main(string[] args)
        {

            //These variables are used to create a
            //random string that will be used as the
            //zip files name
            var chars = "abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            var randFileName = new char[4];
            var random = new Random();

            //Create the zip file name
            for (int i = 0; i < randFileName.Length; i++)
            {
                randFileName[i] = chars[random.Next(chars.Length)];
            }
            string finalString = new String(randFileName);

            Say("Starting file extraction..");

            string day = DateTime.Now.ToString("MM-dd-yy ");
            string userName = Environment.UserName;
            string startDir = $"c:/users/{userName}/test_folder";
            string zipDir = $"c:/users/{userName}/archive/{day}{finalString}.zip";
            string dirName = $"c:/users/{userName}/archive";

            //Check if the directory exists
            Say("Attempting to create archive directory..");
            if (Directory.Exists(dirName))
            {
                MinorErr("Directory already exists, resuming extraction process");
            }
            else
            {
                //Create it if it doesn't
                Warn($"Creating archive directory here: {dirName}");
                Directory.CreateDirectory(dirName);
                Say("Directory created, resuming process..");
            }

            try
            {
                //Attempt to extract to zip file
                Say($"Attempting to extract files into: {zipDir}");
                ZipFile.CreateFromDirectory(startDir, zipDir);
                Success($"Extracted files successfully to: {zipDir}");
            }
            catch (Exception e)
            {
                //Catch any error that occurs during
                //the archiving stage and log the error
                //to a text file for further analysis
                var programPath = System.Reflection.Assembly.GetExecutingAssembly();
                FatalErr($"Something went wrong and the program cannot continue, exiting process with error code {e}..");
                FatalErr("Writing error to file for further analysis.");
                File.WriteAllText($"{programPath}/log/errorlog.txt", e.ToString());
            }

            Say("Press enter to exit..");
            Console.ReadLine();
        }
    }
}

1 comments

@forsvarir 2016-05-24 10:22:50

As has been said in the stack overflow answer, the easiest way to improve performance is to use the alternate overload for ZipFile.CreateFromDirectory that supports you specifying the compression level.

ZipFile.CreateFromDirectory(startDir, zipDir, CompressionLevel.Fastest, false);

This tells the algorithm to prioritize speed over compression, so you trade size for time. Running some tests on my computer, it doesn't look like the compression algorithm has been used to maximize processor usage. It should be possible to improve the performance by using multiple threads to perform the compression, which is why zip products usually offer this as an option. Achieving this is however, a larger undertaking than just calling the library function so again it's a trade off between development time/complexity and run time.

As far as the rest of your code goes, I would consider moving your output methods behind an interface and implementing it in another class.

public interface IReporter {
    string Success(string input);
    string Warn(string input);
    string Say(string input);
    string FatalError(string input);
    string MinorError(string input);
}

public class ConsoleReporter : IReporter {
    public string Success(string input)
    {
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine(input);
        return input;
    }
    // etc
} 

You can then instantiate a version of the concrete class and use it in your processing. This is a small change, however it means that if for example you decided to do a WPF version of your application it could easily be changed to output to a WPF control rather than the console, or you could have a version to write to a logfile rather than the console etc.

It's also a little odd that your output methods (Success, Warn, Say etc) return the string that's been passed into them. Would void be more appropriate. As far as I can see the return value is never used anywhere.

I'm not sure what your restrictions/goals are around the filename however you might also want to have a look at some alternates to GetRandomFileName or create unique filename with a given extension.

@13aal 2016-05-24 15:32:54

I was unable to fully read your answer earlier, I really like the idea of the interface, I'm going to go ahead and implement that, I might also try multi threading, thank you for this answer.

Related Questions

Sponsored Content

1 Answered Questions

Rendering an html page uploaded by a user into MVC app

1 Answered Questions

1 Answered Questions

[SOLVED] Hex Dump Utility in x86-64 Assembly: Version 1.1

3 Answered Questions

[SOLVED] Archiving files into directories

  • 2017-08-23 11:06:23
  • Drag and Drop
  • 142 View
  • 9 Score
  • 3 Answer
  • Tags:   c# file

3 Answered Questions

[SOLVED] “How are you spending your time on the computer?” Part 2

1 Answered Questions

[SOLVED] Compressing a file using zip or gzip

2 Answered Questions

[SOLVED] Speeding Up BufferedWriter

1 Answered Questions

[SOLVED] Speeding up the process of obtaining data

2 Answered Questions

[SOLVED] Process zip files

1 Answered Questions

Sponsored Content