Clean Up Your HDD (source)

I had the time do rework my hddcleaner a bit.
It's now ready to be shown.

Performance has increased dramatically.
Scanning my c and d drives and displaying the results on windows xp using python 2.5 takes now only around 31 seconds.
Memory usage for the task maxes at 77 MB. Tested on a two partition drive with a total of aound 40 GB (some 4-5GB free)

It does what it is supposed to do.

As a default it will look in all drives (windows) or root(unix). You may specify a folder or drive as command line parameter e.g. "HDDCleaner c:\mydrive"

Ok, here is a final version ready for download as exe, python source or simply copy paste from below.

What would be nice for the future is a feature to sort the columns in the frame and to limit the filetypes that are looked for.
Next version perhaps ;)

Exe-Version:

*** binary dependencies *** Your executable(s) also depend on these dlls which are not included, you may or may not need to distribute them. Make sure you have the license if you distribute any of them, and make sure you don't distribute files belonging to the operating system. OLEAUT32.dll - C:\WINDOWS\system32\OLEAUT32.dll USER32.dll - C:\WINDOWS\system32\USER32.dll COMCTL32.dll - C:\WINDOWS\system32\COMCTL32.dll SHELL32.dll - C:\WINDOWS\system32\SHELL32.dll ole32.dll - C:\WINDOWS\system32\ole32.dll WINMM.dll - C:\WINDOWS\system32\WINMM.dll WSOCK32.dll - C:\WINDOWS\system32\WSOCK32.dll comdlg32.dll - C:\WINDOWS\system32\comdlg32.dll ADVAPI32.dll - C:\WINDOWS\system32\ADVAPI32.dll MSVCP71.dll - D:\Programmierung\python25\lib\site-packages\wx-2.8-msw-unicode \wx\MSVCP71.dll GDI32.dll - C:\WINDOWS\system32\GDI32.dll KERNEL32.dll - C:\WINDOWS\system32\KERNEL32.dll gdiplus.dll - D:\Programmierung\python25\lib\site-packages\wx-2.8-msw-unicode \wx\gdiplus.dll RPCRT4.dll - C:\WINDOWS\system32\RPCRT4.dll

SourceVersion:
Needed is wxPython and win32api optional

Source for copy paste:

#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
import sys, os, wx  
from wx.lib.mixins.listctrl import CheckListCtrlMixin  
from stat import *

ID_DELETE=100

def listDrives():  
    if sys.platform == 'win32':  
        try:  
            import win32api,string  
            drives=win32api.GetLogicalDriveStrings()  
            drives=string.splitfields(drives,'\000')  
            return drives  
        except: # in case PyWin is not present we do it the classical way  
            drives = []  
            for i in range(ord('a'), ord('z')+1):  
                drive = chr(i)  
                if(os.path.exists(drive +":\\")):  
                    drives.append(drive+":\\")  
            return drives


def listFreeSpace(drive):  
    try:  
        if sys.platform == 'win32':  
            import win32api,string  
            info=win32api.GetDiskFreeSpaceEx(drive)  
            return info  
    except: # most probably pywin is not present  
        print "Unexpected error:", sys.exc_info()

def listFilesByName(listOfFiles,directory,files):  
    for fileName in files:  
        filepath = os.path.join(directory,fileName)  
        if os.path.isfile(filepath):  
            filesize = os.stat(filepath)[ST_SIZE]  
            listOfFiles[filepath] = filesize

def scan(directories):   
    listOfFiles = {}  
    for directory in directories:   
        sys.stdout.write('Scanning directory '+directory+'...\n')           
        directory = os.path.abspath(directory)  
        os.path.walk(directory,listFilesByName,listOfFiles)         
    sys.stdout.write('Done scanning all dirs. Now sorting and building GUI.\n')  
    allFiles = listOfFiles.items()  
    allFiles.sort(list_compare)  
    sortedList = allFiles  
    return sortedList

def list_compare(listX, listY):  
    if listX[1]>listY[1]:  
        return -1  
    elif listX[1]==listY[1]:  
        return 0  
    else: # x<y  
        return 1

class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin):  
    def __init__(self, parent):  
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)  
        CheckListCtrlMixin.__init__(self)  
        self.log = sys.stdout  
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)

    def OnItemActivated(self, evt):  
        self.ToggleItem(evt.m_itemIndex)

class FilesFrame(wx.Frame):       
    def __init__(self, parent, files):   
        wx.Frame.__init__(   
            self, parent, -1, "HDD Clean", size=(640,480)   
            )   
        p = wx.Panel(self, -1, style=0)   
        b = wx.Button(p, -1, "Delete...")   
        b.SetDefault()   
        self.Bind(wx.EVT_BUTTON, self.OnDelete, b)   
        self.files=files  
        self.list = CheckListCtrl(p)  
        sizer = wx.BoxSizer(wx.VERTICAL)  
        sizer.Add(b, 0, wx.EXPAND)  
        sizer.Add(self.list, 1, wx.EXPAND)  
        p.SetSizer(sizer)

        self.list.InsertColumn(0, "Delete")  
        self.list.InsertColumn(1, "Size",wx.LIST_FORMAT_RIGHT)  
        self.list.InsertColumn(2, "File")  
        self.list.InsertColumn(3, "Type")


        for i in self.files:  
            index = self.list.InsertStringItem(sys.maxint,"")  
            self.list.SetStringItem(index, 1, str(i[1]))  
            self.list.SetStringItem(index, 2, str(i[0]))  
            indexForFileType=str(i[0]).rfind(".")+1  
            filetype="None"  
            if indexForFileType!=0 and (len(str(i[0]))-indexForFileType<10):  
                filetype=str(i[0])[indexForFileType:]  
            self.list.SetStringItem(index, 3, filetype)

        self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)  
        self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)  
        self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)  
        self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE)

        self.Show(1)

    def OnDelete(self, evt):   
        items=self.list.GetItemCount()  
        allItems = range(0,items)  
        allItems.reverse()  
        for item in allItems:  
            if self.list.IsChecked(item):  
                listItem=self.list.GetItem(item,col=2)  
                self.list.DeleteItem(item)  
                os.remove(listItem.GetText())

myapp=wx.PySimpleApp()  
files={}  
if len(sys.argv)>1:  
    files=scan(sys.argv[1:])  
else:  
    allDrives = listDrives()  
    if allDrives==None:  
        files = scan("/")  
    else:  
        files= scan(allDrives)  
if len(files)>0:  
    FilesFrame(None,files)  
    myapp.MainLoop()  
else:  
    print "No files found, exiting !"