Summary: Learn how to generate a report of disk space usage per directory, with subdirectories recursively scanned and added to the totals too.
This month I broke down and wrote a little routine I needed and I thought that it might be of interest to others. Here I sit with 10 gigs of disk space and I am always hitting the limit. Invariably this problem arises because I install stuff all the time and then forget to delete it or I create temporary files outside of the \TEMP directory and forget them too. If you've used any form of Unix, you probably know about the "du" command which tells you how much space is taken up in each directory below the current one. I have an OS/2 port of "du", but it doesn't seem to like network drives and du gives the total for all subdirectories recursively. What I usually want to know is the usage total for each subdirectory of the current directory without listing all the subdirectories under each subdirectory.
Perhaps an example will clarify what I mean. Suppose you are at a command prompt in the F:\OS2APPS directory. That directory has a number of subdirectories like F:\OS2APPS\LOTUS, F:\OS2APPS\DESCRIBE, F:\OS2APPS\PMMAIL, F:\OS2APPS\PMVIEW, and so on. What I usually want is a report that tells me how much space is used by all files underneath each directory. I don't care that there are 14 megs used in F:\OS2APPS\LOTUS\123, 30 megs used in F:\OS2APPS\LOTUS\WORDPRO, and so on. I just want to know that underneath F:\OS2APPS\LOTUS 165 megs are used.
This is actually a pretty simple thing to accomplish in Rexx using the RexxUtil library that comes with OS/2 Rexx. The first step is to determine what directory we are currently in using the Directory() function:
/* Register REXXLIB functions */ call rxfuncadd 'SysLoadFuncs','RexxUtil','SysLoadFuncs' call sysloadfuncs /* Get the directory we are currently in */ RootDir=Directory()
Then we use the SysFileTree() function to get a list of the subdirectories in our current directory. The call looks like this:
The first parameter is the search mask and we use "*" to find all possibilities. The second parameter is a stem variable to store the results in. The third parameter tells the function to search only for directories (the D) and report only the fully qualified pathnames for the directories (the O). (The default is to report other information like date and size in addition to the pathname.) We want to include the space used by files in the current directory so we have to do a little extra work. Once we have all the subdirectories, we need to do another search, this time for files and we do want size information. So, we use SysFileTree() again:
The third parameter tells the function that we want files only (the F) and to scan recursively through any subdirectories (the S). Note the lack of an O in the third parameter, so the results that come back will have extra information like the file size which we need. To pick out the file size and accumulate a sum, we use a loop like this:
Sum=0 Do i=1 to Files.0 Parse Var Files.i Date Time Size . Sum=Sum+Size end /* do */
To organize our code and make it easier to use, we can put these two pieces of code together into a function called DirSize that we can call:
DirSize: Procedure Expose RootDir Parse Arg Dir rc=Directory(Dir) If Dir=RootDir then rc=SysFileTree("*","Files.","F") else rc=SysFileTree("*","Files.","FS") Sum=0 Do i=1 to Files.0 Parse Var Files.i Date Time Size . Sum=Sum+Size end /* do */ Return Sum
Note the IF/THEN structure that determines whether or not we are getting size information in a subdirectory or in the current directory. We want to search subdirectories recursively for files, but we don't want to do that for the current directory. Once the sum has been computed, it is returned to the caller.
Once we have called DirSize for the current directory and all of the subdirectories, all we have to do is format the output and present it to the user. To make the output easy to read, we will want to have the sizes in columns that line up. We should also print out the sizes printed in bytes, kilobytes (units 1024 bytes), and megabytes (units of 1024x1024 bytes).
Formatting the numbers is easy. We just use the RIGHT() function like this:
where Total is the variable that contains the total number of bytes used and the 11 means that we want a field eleven characters wide, padded with spaces on the left if necessary. For the kilobyte and megabyte columns, we use the FORMAT() function:
Format(Total/1024,8,1) /* Total usage in kilobytes */ Format(Total/1048576,5,1) /* Total usage in megabytes */
where the 8 in the kilobyte calculation means we want an 8 character field to the left of the decimal point and the 1 means we want one digit after the decimal point.
To handle the directory names we have to do a little more work. To keep all the columns lined up when we print out the results, the name column has to have a constant length. If we just print out the name of each directory, they will have different sizes. The way to do it is to ensure that the longest name fits in the allotted space and pad the shorter ones with spaces on the right if the name column is printed first. When we do our search for the subdirectories, we keep track of which one has the largest name by comparing the size of the current subdirectory name with the size of the largest one so far. If we store the size of the largest subdirectory name in variable NMax, then we can use the LEFT() function to print out the names:
where SubDir is a variable that contains the subdirectory name.
The sample code (.CMD, 4K) will implement the above functions and return a report on the disk space used in the current directory and in each of its subdirectories. Just copy it to a directory in your PATH statement and then at a command line you can type diskuse to generate a report for the current directory. With last month's sorting routine, it is a simple matter to sort the results by size so that it is easy to see where your disk space has gone, and the sample code does this.
|Copyright © 1998 - Falcon Networking||ISSN 1203-5696||December 1, 1998|