3
\$\begingroup\$

I recently wrote my first C# app that's goal it to take a drive letter and output a CSV list of some basic information. TOTALSPACE,FREESPACE,STATUS.

I've been wondering If it would be possible to make this application even faster. Got any good suggestions?

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace drivespace
{
class Program
{
    static void Main(string[] args)
    {
       //"PATHTOEXE\drivespace.exe" drive-C:
        foreach (String arg in args)
        {
            String[] parts = arg.Split('-');
            if (parts[0].Equals("drive"))
            {
                long toalspace = 0;
                long freespace = 0;
                string status = "NOTFOUND";

                foreach (DriveInfo drive in DriveInfo.GetDrives())
                {
                    if (drive.Name == parts[1] + ":\\")
                    {
                        if (drive.IsReady)
                        {
                            toalspace = drive.TotalSize;
                            freespace = drive.TotalFreeSpace;
                            status = "READY";
                        }
                        else
                        {
                            status = "NOTREADY";
                        }
                        break;
                    }
                }
                //TOTALSPACE,FREESPACE,STATUS
                Console.WriteLine(toalspace.ToString() + "," + freespace.ToString() + ',' + status);
            }
        }
    }
}
}

https://github.com/keverw/drivespace is the Github page, it might have some more useful info.

\$\endgroup\$
5
  • \$\begingroup\$ I'm assuming that DriveInfo is a class..... Possibly provide us with that? \$\endgroup\$ Commented May 6, 2012 at 2:57
  • \$\begingroup\$ Program.cs is the whole program. \$\endgroup\$
    – Keverw
    Commented May 6, 2012 at 23:17
  • \$\begingroup\$ But DriveInfo isn't built into c# \$\endgroup\$ Commented May 7, 2012 at 0:17
  • \$\begingroup\$ It's part of System.IO, msdn.microsoft.com/en-us/library/system.io.driveinfo.aspx \$\endgroup\$
    – Keverw
    Commented May 7, 2012 at 4:15
  • \$\begingroup\$ Oh sorry for my cluelessness \$\endgroup\$ Commented May 7, 2012 at 12:33

3 Answers 3

2
\$\begingroup\$

Here's a really squished down version of the code that should run a bit quicker too.

    private static void Main(string[] args)
    {
        // "PATHTOEXE\drivespace.exe" drive-C
        var driveInfo = DriveInfo.GetDrives().ToDictionary(drive => drive.Name);

        foreach (var drive in args
            .Select(arg => arg.ToUpperInvariant().Split('-'))
            .Where(parts => (parts.Length == 2) && parts[0].Equals("DRIVE") && driveInfo.ContainsKey(parts[1] + ":\\"))
            .Select(parts => driveInfo[parts[1] + ":\\"]))
        {
            // TOTALSPACE,FREESPACE,STATUS
            Console.WriteLine(
                (drive.IsReady ? drive.TotalSize : 0L) + "," +
                (drive.IsReady ? drive.TotalFreeSpace : 0L) + "," +
                (drive.IsReady ? "READY" : "NOTREADY"));
        }
    }
\$\endgroup\$
2
\$\begingroup\$

It is possible to make the application faster (but I am not sure that you will notice the difference unless you call the application with many arguments and have many drives). The main problem with the code is that you iterate through all the arguments, and for each argument you iterate through all the drives until you find the matching drive-letter.

So if the the application is called with an unknown drive-letter 10 times (as in "PATHTOEXE\drivespace.exe" drive-X drive-X drive-X drive-X ... and if you have 15 drives mounted, then DriveInfo.GetDrives() will be called 10 times and the line if (drive.Name == parts[1] + ":\\") will be executed 150 times. To avoid this you could store the drive information in a dictionary and then just lookup the matching drive in near constant time.

Notice below that I have changed the format of the arguments to the application to DriveSpace.exe C D X to avoid the parsing of the individual argument.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Drivespace
{
    class Program
    {
        static void Main(string[] args)
        {
            var allDrives = DriveInfo.GetDrives().ToDictionary(drive => drive.Name);

            foreach (String arg in args)
            {
                DriveInfo driveInfo;
                if (allDrives.TryGetValue(arg + @":\", out driveInfo))
                {
                    if (driveInfo.IsReady)
                    {
                        WriteOutput(driveInfo.TotalSize, driveInfo.TotalFreeSpace, "READY");
                    }
                    else
                    {
                        WriteOutput(0, 0, "NOTREADY");
                    }
                }
                else
                {
                    WriteOutput(0, 0, "NOTFOUND");
                }
            }
        }

        private static void WriteOutput(long totalSize, long freeSpace, string status)
        {
            Console.WriteLine(String.Format("{0},{1},{2}", totalSize, freeSpace, status));
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

To take Jesse C. Slicer's answer a bit further.. I cleaned up the code to use constants and string.Format... It makes more sense from an architectural stand point. Sealing the class is also a performance boost for JIT, but the benefit should be minimal at best. As stated in this other stack overflow post, it's more of a late result type of performance enhancement. You more than likely won't see anything from it.

internal sealed class Program
    {
        private const string READY = "READY";
        private const string NOT_READY = "NOTREADY";
        private const string DRIVE = "DRIVE";

        private static void Main(string[] args)
        {
            var driveInfoDictionary = DriveInfo.GetDrives().ToDictionary(d => d.Name);

            foreach (var drive in args
                .Select(arg => arg.ToUpperInvariant().Split('-'))
                .Where(parts => (parts.Length == 2) && parts[0].Equals(DRIVE) && driveInfoDictionary.ContainsKey(string.Format("{0}:\\", parts[1])))
                .Select(parts => driveInfoDictionary[string.Format("{0}:\\", parts[1])]))
                    Console.WriteLine("{0},{1},{2}",
                                      (drive.IsReady ? drive.TotalSize : 0L),
                                      (drive.IsReady ? drive.TotalFreeSpace : 0L),
                                      (drive.IsReady ? READY : NOT_READY));
        }
    }

https://stackoverflow.com/questions/2134/do-sealed-classes-really-offer-performance-benefits

\$\endgroup\$
1
  • \$\begingroup\$ Better yet, make it a static class since there are no instance methods or data. \$\endgroup\$ Commented May 11, 2012 at 21:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.