Reading directory entries
There are three means of reading directory entries, each intended for a particular purpose.
Using readdir
Sending the readdir message to a CfsDirectoryDescriptor instance causes the instance to answer a new CfsDirectoryEntry instance representing the next directory entry matching the specified pattern and type. A CfsDirectoryEntry instance understands the same messages as a CfsStat instance, plus the dName message, which answers the name of the file represented by the directory entry as a string. See Testing existence and obtaining other file properties for a description of the messages understood by a CfsStat instance.
When there are no more directory entries to be read, the readdir message answers nil. An example of the use of readdir follows:
"Answer a collection containing directory entries for all regular files
and directories in 'c:\'"
| collection dd de |
collection := OrderedCollection new.
(dd := CfsDirectoryDescriptor
opendir: 'c:\'
pattern: '*' mode: FREG | FDIR) isCfsError
ifTrue: [^self error: dd message].
[(de := dd readdir) notNil]
whileTrue: [collection add: de].
dd closedir.
^collection.
Using readdir:
The readdir: message is identical in behavior to readdir, except that instead of creating a new CfsDirectoryEntry instance, it stores the directory information in the CfsDirectoryEntry instance supplied as an argument. This technique provides better performance than creating and discarding a directory entry for each item in the directory. An example follows:
"Print all regular files and directories in the current working
directory to the transcript"
| dd de |
"Because directory entry data can be discarded after being printed,
there is no point in creating a separate directory entry for each item
read. Instead reuse the same directory entry instance."
de := CfsDirectoryEntry new.
(dd := CfsDirectoryDescriptor
opendir: CfsDirectoryDescriptor getcwd
pattern: '*'
mode: FREG | FDIR) isCfsError
ifTrue: [^self error: dd message].
[(dd readdir: de) notNil]
whileTrue: [Transcript cr; show: de printString].
dd closedir.
Using readdirName
Sending the readdirName message to a CfsDirectoryDescriptor instance answers a string that is the name of the next directory entry matching the specified pattern and type. If there are no more entries, it answers nil.
Tip:
Do not use readdirName followed by CfsStat>>stat: to get file information, because this is never faster than using readdir or readdir:, and forces some platforms to search the directory twice. Using readdir: is the most efficient technique if more than the file names are needed.
If only the file names are required, using readdirName is more efficient than other techniques. Two examples are shown below.
"Print the names of all files in the current working directory to the
Transcript"
| dd name |
(dd := CfsDirectoryDescriptor
opendir: '.'
pattern: '*'
mode: FREG | FDIR | FSPECIAL) isCfsError
ifTrue: [^self error: dd message].
[(name := dd readdirName) isNil]
whileFalse: [Transcript cr; show: name].
dd closedir.
"Count the number of files ending in '.new' in the subdirectory called
'work' that is located under the current working directory and
answer the result"
| dd count |
(dd := CfsDirectoryDescriptor
opendir: 'work'
pattern: '*.new'
mode: FREG | FDIR | FSPECIAL) isCfsError
ifTrue: [^self error: dd message].
count := 0.
[dd readdirName isNil]
whileFalse: [count := count + 1].
dd closedir.
^count
Tip:
For maximum efficiency when using readdirName, ensure that the mode argument is the inclusive-OR of FREG, FDIR and FSPECIAL. Specifying that all file types are to be matched eliminates an operating system call to determine the file type, which would otherwise be needed on some platforms.
Last modified date: 01/29/2015