1
\$\begingroup\$

I have a complex directory structure on my web server that includes .tar files for download; I'm trying to create a report on the size distribution of these files (e.g. 10 are less than 1MB, two are 1-2MB, three are 2-3MB...)

Is there a better way to organize this code? I started it as a console application, writing directly in the Main() function. Now I'm taking a step back and thinking about improvements.

public class MyClass
{
    private static int counter = 0;
    private static Dictionary<int, int> sizeMap = new Dictionary<int, int>()
        {
              {0, 0}
            , {1, 0}
            , {2, 0}
            , {3, 0}
            , {4, 0}
            , {5, 0}
            , {6, 0}
            , {7, 0}
            , {8, 0}
            , {9, 0}
            , {10, 0}
            , {20, 0}
            , {30, 0}
            , {40, 0}
            , {50, 0}
            , {75, 0}
            , {100, 0}
            , {999, 0}
        };
    static void Main(string[] args)
    {
        DirectoryInfo cloud1 = new DirectoryInfo("C:\\brian");
        IEnumerable<DirectoryInfo> cloud1Dirs = cloud1.EnumerateDirectories();
        foreach (var dir in cloud1Dirs)
        {
            ParseDir(dir);
        }
        Console.WriteLine("==================================================");
        foreach (int i in sizeMap.Keys)
        {
            Console.WriteLine(i + "M\t" + sizeMap[i]);
        }
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

    private static void ParseDir(DirectoryInfo currentDir)
    {
        if (counter++ > 1000)
        {
            return;
        }
        IEnumerable<FileInfo> tarFiles = currentDir.EnumerateFiles("*.tar");
        if (tarFiles.Count() > 0)
        {
            foreach (FileInfo tarFile in tarFiles)
            {
                int megLength = (int)(tarFile.Length / 1048576);
                int key = MakeDictionaryKey(megLength);
                sizeMap[key]++;
                Console.WriteLine(tarFile.Name + "\t" + megLength + "M");
            }
        }
        else
        {
            foreach (var dir in currentDir.EnumerateDirectories())
            {
                ParseDir(dir);
            }
        }
    }

    private static int MakeDictionaryKey(int n)
    {
        if (n <= 10) {
            return n;
        } else if (n <= 50) {
            return (int) Math.Ceiling(n / 10.0) * 10;
        } else if (n <= 75) {
            return 75;
        } else if (n <= 100) {
            return 100;
        } else {
            //Really large file!
            return 999;
        }
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Is Foo the actual name of the method? \$\endgroup\$ May 7 '14 at 18:35
  • \$\begingroup\$ Oops! It started that way, but I changed it to ParseDir. \$\endgroup\$
    – Brian
    May 7 '14 at 18:37
2
\$\begingroup\$

The biggest complaint I would have with this code is that you're essentially defining your size map twice. Imagine if you decide you don't want to report on files between 50 and 75MB - you remove the "75" entry from the dictionary, but forget to remove it from the MakeDictionaryKey method, and your program will occasionally fail at runtime.

First, I'd consider modifying your dictionary so instead of using "999" as a synonym for "really big file", you use int.MaxValue:

        , {100, 0}
        , {int.MaxValue, 0}

In your MakeDictionaryKey method, you're then looking for the smallest key value where the key value is greater than the file size you've provided to it. With a bit of LINQ, that simply becomes:

private static int MakeDictionaryKey(int n)
{
   return sizeMap.Keys.Where(x => x <= n).Min();
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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