du for Windows
I often need to get a list of the largest files and directories on my drive. I always used the Unix ‘du’ command to do this — just du -k, sort in reverse and head 50. When I switched to using Windows, I used the ‘du’ found in the Windows binaries of the gnu utilities, then later as those became unavailable, the cygwin utilities.
But cygwin is fat, and I have always wanted a better way. Recently I started using Vista’s “find” feature to get a list of all files above a certain size, then sort. But it’s incredibly slow. My latest look for tools found the sysinternals ‘du’, which has a lot of features, but not what I need.
Finally, I bit the bullet and spent the 10 minutes necessary to write my own. Well, I was rusty and I was half-asleep on an airplane, so it really took 30 minutes. I’m posting the code here for you, so that you can save yourself a whole 30 minutes of effort next time you need to find the largest files on a volume.
Usage: du [drive:|.|*]
I run the command like “du c:\ >sizes.txt” and then open sizes.txt. Finally, back to the comfort of my Unix days, and 10x faster besides. It’s almost the same feeling as when Napster came out and I could find Alan Parsons Project music again.
static void Main(string[] args) { List<KeyValuePair<string, long>> entries = new List<KeyValuePair<string,long>>(); string path; path = args[0]; if (path == “.”) path = Directory.GetCurrentDirectory(); if (path == “*”) { foreach (string drive in Directory.GetLogicalDrives()) { CalculateSize(drive, entries); } } else CalculateSize(path, entries); foreach (KeyValuePair<string,long> kvp in entries) { Console.WriteLine(“{0}t{1}”, kvp.Value, kvp.Key); } } static long CalculateSize(string path, List<KeyValuePair<string, long>> entries) { long cumulativeSize = 0; string[] files; try { files = Directory.GetFiles(path); } catch (Exception ex) { return -1; } foreach (string filename in files) { FileInfo f = new FileInfo(filename); OrderedInsert(filename,f.Length,entries); cumulativeSize += f.Length; } foreach (string dirname in Directory.GetDirectories(path)) { cumulativeSize += CalculateSize(dirname, entries); } OrderedInsert(path, cumulativeSize,entries); return cumulativeSize; } static void OrderedInsert(string path, long size, List<KeyValuePair<string, long>> entries) { KeyValuePair<string, long> entry = new KeyValuePair<string, long>(path, size); int lower = 0; int upper = entries.Count; while (upper > lower + 1) { int middle = lower + (int)Math.Floor((double)(upper - lower) / 2); if (entries[middle].Value < entry.Value) upper = middle; else if (entries[middle].Value > entry.Value) lower = middle; else { entries.Insert(middle, entry); return; } } if (entries.Count == 0) { entries.Insert(0, entry); return; } if (entry.Value > entries[lower].Value) entries.Insert(lower, entry); else entries.Insert(upper, entry); }