Category: Utilities
Author/Contact Info BatGnat
Description: I originally designed this for finding files over nnMb's in size, so I could keep track of what was filling up the HDD array at work. I later extended it to include the ability to read in a file of extensions(so you can find out where all the MP3's are). It will output all files found to a "sizefile.csv" file (or XLS if switch is set), with path/name, size, last accessed, and last modified.

It will currently only run on Win32, but i'm sure it could be modified.

I have only been programming PERL for about 9 months, and have wrote this from scratch, with help from my HTML and Books.

This was originally done as a 4dos batch, but it lacked certain capabilities, so I learned perl, just to write this.

Any Comments and suggestions are welcome.

PS if anyone is interested, i have a copy of all older versions of this software.
# Sizefile.pl

$version="2.1.2";                            # Sizefile version Number
#
#    History
#    -------
#    v2.1.2    Changed some things that "use warnings;" suggested.
#    v2.1.1    Moved some of Subroutines into my own package MySubs.
#    v2.1.0    Optimised the search engine some more (Major rewrite of
+ logic).
#    v2.0.5    Some more optimisations.
#    v2.0.4    Changed it to use Getopt::Long for command line input.
#    v2.0.3    Did some Optimisation on the code for speed.
#    v2.0.2    Changed the CSV output to a sub routine, and finished b
+asic XLS output.
#    v2.0.1    Added beginnings of Excel OLE Support.
#    v2.0.0    Changed it to use Win32::Console, (Prettier interface).
#    v1.6.2    Changed some cosmetic stuff, Cleaned out some old stuff
+ that wasn't needed.
#    v1.6.1    Added History, Added Total Sum to CSV_OUT, Added list o
+f dirs that couldn't be opened.
#    v1.6.0    Put updated version of the original search engine back 
+in, due to File::Find wont let me control errors concerning opening D
+IRS.
#    v1.5.1    Added Pod Documentation
#

#### Load Modules
use Cwd;
use Win32::Console;
use Win32::OLE;
use Getopt::Long;

###### Set default values for incoming variables.
$start_time = localtime($^T);
$original_path = getcwd();
$console = new Win32::Console(STD_OUTPUT_HANDLE);
($X,$Y) = $console->Size();

GetOptions(
                    "path=s"        => \$SEARCH_PATH,
                    "file=s"            => \$FILES_IN,
                    "gt=s"            => \$MORE_THAN,
                    "lt=s"            => \$LESS_THAN,
                    "list=s"            => \$LIST_FILE,
                    "help!"            => \$HELP,
                    "prompt!"        => \$PROMPT,
                    "true!"            => \$REAL_MEGABYTE,
                    "open!"            => \$OPEN_CSV,
                    "xls!"            => \$DOEXCEL,
                    "examples!"    => \$EXAMPLES
            ) || &Help_for_Sizefile;

&Help_for_Sizefile if $HELP;
&show_examples if $EXAMPLES;
&Prompt_for_input if $PROMPT;

if ($LIST_FILE && (-e $LIST_FILE)) {
    open (list_in_from_file, "<$LIST_FILE") || die "\n*** ERROR OPENIN
+G $FILE ***\n";
    chomp (@files_to_search_for = <list_in_from_file>);
    close list_in_from_file;
} else {
    @files_to_search_for = split /;/,$FILES_IN || '*.*'; # Default sea
+rch if none specified
}

$path_to_search = $SEARCH_PATH || getcwd();                # Default p
+ath if none specified = Current Path
$file_must_be_less_than = $LESS_THAN || "9999M";        # Default less
+ than size if none specified
$file_must_be_more_than = $MORE_THAN || "0";        # Default less tha
+n size if none specified

############################

### Signal Handlers ###
$SIG{__WARN__} = \&warn_handle;
$SIG{STOP} = \&sig_int;
##########################

$console->Title ("Sizefile.pl v$version");
&CONSOLE_BORDER();
$rect = $console->ReadRect(2, 9, $X - 3, $Y - 3);
CENTER_LINE("Sizefile v$version by Martin Bowers", 2, $FG_YELLOW);
CENTER_LINE("--------------------------------", 3, $FG_RED);

chdir $path_to_search || die "\n*** Error opening $path_to_search ***\
+n"; # this sets the path into a true filename
$path_to_search = getcwd();
$path_to_search =~ s/\/$//gi;

@orig_files_to_search_for = @files_to_search_for;
PRINT_LINE("Path = $path_to_search", 2, 4, $FG_GRAY);
map {$LIST .= "$_ "} @files_to_search_for;
PRINT_LINE("File = ".substr($LIST, 0, $X - 14)."...", 2, 5, $FG_GRAY) 
+if length($LIST) > $X - 20;
PRINT_LINE("File = @files_to_search_for", 2, 5, $FG_GRAY) if length($L
+IST) < $X - 20;
undef $LIST;
PRINT_LINE("> $file_must_be_more_than", 60, 4, $FG_GRAY);
PRINT_LINE("< $file_must_be_less_than", 70, 4, $FG_GRAY);
PRINT_LINE("Started @ $start_time", 2, 7, $FG_YELLOW);

foreach (@files_to_search_for) {
    s/\./\\\./gi;
    s/\*/.*/gi;
    s/\?/./gi;
}

$F = join '$|^', @files_to_search_for;

foreach ($file_must_be_more_than, $file_must_be_less_than) {
    if (/k/i) {
        if ($REAL_MEGABYTE) {
            s/k//i;
            $_ *= 1024;
        } else {
            s/k/000/i;
        }
    } elsif (/m/i) {
        if ($REAL_MEGABYTE) {
            s/m//i;
            $_ *= 1048576;
        } else {
            s/m/000000/i;
        }
    }
}

die "\n*** ERROR ***\n\n  -lt < -gt\n\n*** ERROR ***\n" if $file_must_
+be_less_than < $file_must_be_more_than;

SEARCH($path_to_search); 
$end_time = localtime;

if ($DOEXCEL) {&do_excel_out;} else {&do_csv_out;}

PRINT_LINE("Finished @ $end_time", 2, $Y - 3, $FG_YELLOW);
PRINT_LINE("Total size = ".&COMMA($total_size)." bytes in ".&COMMA(sca
+lar @files_found)." files", 2, $Y - 2, $FG_YELLOW) if scalar @files_f
+ound >0;
PRINT_LINE("No files found matching that critera!", 2, $Y - 3, $FG_LIG
+HTRED) if scalar @files_found <1;

if ($OPEN_CSV && scalar @files_found >0) {
    chdir $original_path;
    exec "sizefile.csv";
}
print "\n"x $Y;
exit;

##### SUBROUTINES #####
sub Help_for_Sizefile {        # Help subroutine, prints help
    $console->Title ("Sizefile.pl v$version");
    console_border();
    CENTER_LINE("Sizefile v$version by Martin Bowers",2,$FG_YELLOW);
    CENTER_LINE("--------------------------------",3,$FG_RED);

    my $line = 4;
    PRINT_LINE("Sizefile.pl HELP",3,$line++,$FG_YELLOW);    $line++;
    PRINT_LINE("sizefile.pl [-path path] [-file filename] [-gt size] [
+-lt size]",3,$line++,$FG_WHITE);    $line++;
    PRINT_LINE("This program has five parameters:",3,$line++,$FG_WHITE
+);    $line++;
    PRINT_LINE("   -path path             specifies the path of the se
+arch",3,$line++,$FG_WHITE);
    PRINT_LINE("   -file file[,file,,,]   the file name to search for"
+,3,$line++,$FG_WHITE);
    PRINT_LINE("   -gt size               file must be greater than th
+is size",3,$line++,$FG_WHITE);
    PRINT_LINE("   -lt size               file must be less than this 
+size",3,$line++,$FG_WHITE);
    PRINT_LINE("   -true                  Set GT/LT to use real megaby
+tes (1,048,576bytes)",3,$line++,$FG_WHITE);
    PRINT_LINE("   -list file.txt         get file list from file.txt"
+,3,$line++,$FG_WHITE);
    PRINT_LINE("   -prompt                prompts user for details",3,
+$line++,$FG_WHITE);
    PRINT_LINE("   -xls                   generates XLS file instead o
+f CSV",3,$line++,$FG_WHITE);
    PRINT_LINE("   -examples              displays examples",3,$line++
+,$FG_WHITE);
    PRINT_LINE("   -help                  this screen",3,$line++,$FG_W
+HITE);
    exit;
}

sub show_examples {
    my $line=4;
    PRINT_LINE("Examples:",3,$line++,$FG_YELLOW);
    $line++;
    PRINT_LINE('sizefile.pl -path \\\\sau01dat01\z$           find all
+ files on <--',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -file *.bat                     find *.bat
+ file here and down',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -gt 10m                         find file 
+> than 10Mb',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -lt 10k                         find file 
+< than 10Kb',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -path d:\ -file *.dl? -gt 10m   find *.dl?
+ on d:\ > than 10m',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -path d:\ -file *.exe,*.com     find *.com
+ and *.exe',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -file [az]*.*                   a*.dll and
+ z*.dll',3,$line++,$FG_WHITE);
    PRINT_LINE('sizefile.pl -file [a..l]*.*                 a*.*,b*.*,
+ ... , l*.* ',3,$line++,$FG_WHITE);
    exit;
}

sub Prompt_for_input {
    print "\nPlease enter what you want to search for: ";
    chomp (my $tempfile = <STDIN>);
    @files_to_search_for = split /,/,$tempfile if ($tempfile ne '');
    print "Please enter the path for the search: ";
    chomp (my $temppath = <STDIN>);
    if ($temppath ne '') {$path_to_search = $temppath;}
    print "The file should be greater than: ";
    chomp (my $tempfsgt = <STDIN>);
    if ($tempfsgt ne '') {$file_must_be_more_than = $tempfsgt;}
    print "The file should be less than: ";
    chomp (my $tempfslt = <STDIN>);
    if ($tempfslt ne '') {$file_must_be_less_than = $tempfslt;}
    print "\n";
}

sub ole_out {
    my $TEXT = shift;
    my $COL = shift;
    my $ROW = shift;

    $sheet->Cells($ROW,$COL)->{Value} = $TEXT;
}

sub warn_handle {
    my $time = localtime;
    print "$time\t***WARN***\t $_[0]";
}

sub sig_int {
    my $signal = shift;
    close csv_out;
    print "SOMEONE WANTS OUT!!!!!\n"x20;
    $SIG{$signal} = \&sig_int;
}

sub do_excel_out {
    # use existing instance if Excel is already running
    eval {$EXCEL = Win32::OLE->GetActiveObject('Excel.Application')};
    die "Excel not installed" if $@;
    unless (defined $EXCEL) {
        $EXCEL = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit
+;})
        or die "Oops, cannot start Excel";
    }

    # get a new workbook
    $book = $EXCEL->Workbooks->Add;
    $sheet = $book->Worksheets(1);
    $book->{"ActiveSheet"}->{"Name"} = "Sizefile";
    ole_out("Generated by Sizefile v$version - written by Martin Bower
+s", 1, 1);
    ole_out("Started @ $start_time", 1, 2);
    ole_out("Path = $path_to_search", 1, 3);
    ole_out("File = @orig_files_to_search_for", 2, 3);
    ole_out("> $file_must_be_more_than but", 3, 3);
    ole_out("< $file_must_be_less_than", 4, 3);
    ole_out("Filename", 1, 5);
    ole_out("Filesize", 2, 5);
    ole_out("Access", 3, 5);
    ole_out("Modified", 4, 5);

    my $start_pos = 6;
    map {
        my ($filename,$filesize,$access,$modified) = split /,/,$_;
        ole_out($filename, 1, $start_pos);
        ole_out($filesize, 2, $start_pos);
        ole_out($access, 3, $start_pos);
        ole_out($modified, 4, $start_pos);
        $start_pos++;
    } @files_found;

    ole_out("Total Sum", 1, scalar @files_found + 6);
    ole_out("=sum(b6:b". (scalar @files_found + 5) .")", 2, scalar @fi
+les_found + 6);
    ole_out("Finished @ $end_time", 1, scalar @files_found + 8);
    $book->SaveAs( "$original_path/SIZEFILE.xls");
    undef $book;
    undef $EXCEL;

}

sub do_csv_out {
    open (csv_out, ">$original_path/sizefile.csv") || die "*** ERROR O
+PENING sizefile.csv - File may be in use ***\n";
    print csv_out "Generated by Sizefile v$version - written by Martin
+ Bowers\n";
    print csv_out "Started @ $start_time\n\n";
    print csv_out "\nPath = $path_to_search\nFile = @orig_files_to_sea
+rch_for\n> $file_must_be_more_than but < $file_must_be_less_than\n";
    print csv_out "Filename,Filesize,Access,Modified\n";
    map {print csv_out "$_\n";} @files_found;
    print csv_out "Total Sum,=sum(b9:b".(scalar @files_found + 8).")\n
+" if scalar @files_found >0;
    map {print csv_out $_;} @dir_error_list;
    print csv_out "\n\nFinished @ $end_time";
    close csv_out || warn "*** ERROR CLOSING CSV_OUT ***\n";
}

sub SEARCH {
    push @PATH, shift;
    my $PATH = join "/", @PATH;
    opendir (DIR, "$PATH/") || &dir_error($PATH, $COL, $ROW);
    my @FILES = readdir(DIR);
    closedir DIR;

    CENTER_LINE("-" x $X, $Y - 1, $FG_WHITE);
    CENTER_LINE($PATH, $Y - 1, $FG_YELLOW);

    foreach $FILE (@FILES) {
        $COL = $COL || 1;
        $ROW = $ROW || 9;
        if ($COL > $X - 4) {
            $COL=1;
            $ROW++;
            if ($ROW > $Y - 5) {
                $ROW = 9;
                $console->WriteRect($rect, 2, 9, $X - 3, $Y - 3)
            }
        }
        $COL++;

        if (-d "$PATH/$FILE") {
            PRINT_LINE(".", $COL, $ROW, $FG_WHITE);
            &SEARCH($FILE) if ($FILE !~ /^\./);
        } else {
            if ($FILE =~ /^$F$/gi) {
                my $size_of_file = -s "$PATH/$FILE";
                if ($size_of_file >= $file_must_be_more_than && $size_
+of_file <= $file_must_be_less_than) {
                    $total_size += $size_of_file;
                    my @file_info = stat "$PATH/$FILE";
                    my @raw_access_time = localtime($file_info[8]);
                    my @raw_modify_time = localtime($file_info[9]);
                    undef @file_info;
                    my $last_access_date = ($raw_access_time[3])."/".(
+$raw_access_time[4]+1)."/".($raw_access_time[5]+1900);
                    my $last_modify_date = ($raw_modify_time[3])."/".(
+$raw_modify_time[4]+1)."/".($raw_modify_time[5]+1900);
                    PRINT_LINE("*", $COL, $ROW, $FG_LIGHTGREEN);
                    push @files_found, "$PATH/$FILE,$size_of_file,$las
+t_access_date,$last_modify_date";
                } else {
                    $COL--;
                }
            } else {
                $COL--;
            }
        }
    }
    pop @PATH;
    return $total_size;
}

sub dir_error { # for when opendir fails
    my $DIR = shift;
    my $COL = shift;
    my $ROW = shift;
    PRINT_LINE("X", $COL, $ROW, $FG_LIGHTRED);
    push @dir_error_list, "\nERROR opening DIR $DIR";
    undef $DIR, $COL, $ROW;
}

sub COMMA {
        local $_  = shift;
        1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
        return $_;
    }

sub CONSOLE_BORDER {
    $::console->Cls($::FG_WHITE | $::BG_BLUE);
    $::console->FillChar('-', $::X, 0, 0);
    for $y (1..$::Y - 1) {
        $::console->FillChar('|', 1, 0, $y);
        $::console->FillChar('|', 1, $::X - 1, $y);
    }
    $::console->FillChar('-', $::X, 0, $::Y - 1);
}

sub CENTER_LINE {
    my $string= shift;
    my $line_no = shift;
    my $COLOR = shift || $::FG_LIGHTRED;
    my $line_length = length($string);
    my $center = int(($::X - $line_length) / 2);
    $::console->FillAttr( $COLOR | $::BG_BLUE, $line_length, $center, 
+$line_no);
    $::console->WriteChar($string, $center, $line_no);
}

sub PRINT_LINE {
    my $string= shift;
    my $col = shift;
    my $row = shift;
    my $COLOR = shift || $::FG_LIGHTRED;
    my $line_length = length($string);

    $::console->FillAttr( $COLOR | $::BG_BLUE, $line_length, $col, $ro
+w);
    $::console->WriteChar($string, $col, $row);
    undef $string, $col, $row, $color, $line_length;
}

sub CLR_LINE {
    my $LINE = shift;
    $::console->WriteChar(" " x ($::X - 3), 1 ,$LINE);
    undef $LINE;
}