Listing the contents of a directory
by Richard Russell, March 2010
The main BBC BASIC for Windows documentation explains how to list the contents of a disk directory and more detail is provided in the article Scanning a Directory (Reading Directory Entries), but both require the code to be adapted to the needs of the programmer. Some dialects of BASIC provide a built-in means of extracting the contents of a directory to a string array, for example Liberty Basic's FILES statement; this can be a more straightforward approach and avoids the need to work directly with the Windows API.
The function FNfiles listed below provides a similar capability in BBC BASIC. It takes two parameters, a filter string to determine the directory (folder) and files to be scanned, and an array in which to return the results, for example:
nfiles% = FNfiles("C:\Windows\*.*", file$())
Here the array file$() is filled with a list of all the files and sub-directories in C:\Windows\ (starting at index zero), and the total number of entries is returned from the function. For each file or directory four items of information are returned as follows:
file$(I%,0) | The name of the file or sub-directory |
file$(I%,1) | The size of the file, as a decimal string |
file$(I%,2) | The 'last modified' time stamp, in TIME$ format |
file$(I%,3) | A set of attribute bits, as a hexadecimal string |
The main attribute bits are (in hexadecimal):
01 | Read only |
02 | Hidden |
04 | System |
10 | Directory |
20 | Archive |
If necessary the array will be created by the function; it is not essential to DIMension it yourself. However if the array already exists, but is not big enough to contain the data, it will be discarded and a new array created. Since this will result in memory being lost, if you intend to call the function multiple times it is better to create an array big enough to hold the largest amount of data you are likely to need, for example:
DIM file$(1000,3) nfiles% = FNfiles("C:\Windows\*.*", file$())
If you want to list only a certain type of file, you can specify the filter string accordingly:
nfiles% = FNfiles("C:\Program Files\BBC BASIC for Windows\*.exe", file$())
The function may also be used as a means of detecting the existence of a file:
exists% = FNfiles("C:\pagefile.sys", file$())
This will return 1 if the file exists and 0 otherwise.
Here is the function itself:
DEF FNfiles(filter$, RETURN array$()) LOCAL @%, D%, H%, I%, N%, P%, R%, S%, T%, size# DIM D% LOCAL 317, S% LOCAL 15, T% LOCAL 24 @% = &1001010 IF !^array$() N% = DIM(array$(),1)+1 FOR P% = 0 TO 1 I% = 0 SYS "FindFirstFile", filter$, D% TO H% IF H% <> -1 THEN REPEAT IF P% THEN size# = D%!28 * 2.0#^32 + (D%!32 >>> 1)*2 + (D%!32 AND 1) SYS "FileTimeToSystemTime", D%+20, S% SYS "GetDateFormat", 0, 0, S%, "ddd.dd MMM yyyy,", T%, 17 SYS "GetTimeFormat", 0, 0, S%, "HH:mm:ss", T%+16, 9 array$(I%,0) = $$(D%+44) array$(I%,1) = STR$(size#) array$(I%,2) = $$T% array$(I%,3) = STR$~!D% ENDIF I% += 1 SYS "FindNextFile", H%, D% TO R% UNTIL R% = 0 SYS "FindClose", H% ENDIF IF P% = 0 IF N% < I% THEN IF N% array$() = "" !^array$() = 0 DIM array$(I%-1,3) ENDIF NEXT P% = I%