3

I've used <cfdirectory> to get only directories, but I need to do this inside a UDF written in cfscript, so I need to use DirectoryList(). It appears that I need to get everything and then visit the result filtering directories manually. However, there is a filter parameter... can it be used to filter only directories? If so, what would be the filter?

I haven't found an example that will return only directories, and the documentation is not clear on what can be filtered (except for *.txt).

Redtopia
  • 4,947
  • 7
  • 45
  • 68
  • Not sure exactly what your use case is, but could you loop through the directory list (after you have the results) and filter out anything with an extension to remove all files? – Matt Busche Apr 22 '12 at 14:08

5 Answers5

5

<cfdirectory action="list"...> (and DirectoryList(path [,recurse] [,listInfo="query"]...)) returns a query object. There's no reason you couldn't do that and then immediately do a query-of-queries filtering on the TYPE column.

Mark Kruger reminds me that I should probably include code:

<cffunction name="DirectoryList2" returntype="query">
  <cfargument name="dirPath" type="string" required="true">
  <cfif directoryExists(arguments.dirPath)>
    <cfdirectory directory="#arguments.dirPath" name="local.DirQuery" action="LIST">
    <cfquery name="local.DirQuery" dbtype="query">
    SELECT * FROM local.DirQuery WHERE TYPE = 'dir'
    </cfquery>
    <cfreturn local.DirQuery>
  <cfelse>
    <cfthrow message="No such directory">
  </cfif>
</cffunction>
ale
  • 6,369
  • 7
  • 55
  • 65
  • Doing it once and wrapping it in a UDF (DirectoryList2) would certainly keep you from having to do it every single time. – ale Apr 23 '12 at 12:59
  • 1
    Yeah, it sounds like you will want a wrapper function either way (ie using `DirectoryList` + QoQ or `fdirectory`). An additional advantage of Al's approach is it can be used in all cfscript components. About the only difference is where the filtering is done. If you typically had a *lot* more files than directories, it might be slightly more efficient to use a wrapper of `cfdirectory`. Otherwise, it probably does not make much difference. – Leigh Apr 23 '12 at 20:21
  • Not sure why you would do this... you can get a list of directories using cfdirectory using the type attribute, so the extra code is unnecessary. The question was specific to using DirectoryList due to it being in cfscript block, so any answer should take that into account. – Redtopia Apr 24 '12 at 20:49
  • @Redtopia: Well, then, the answer to your question is "No". But since that's not very helpful, the several of us who answered opted for the "No, but you can do this thing which comes close" answer instead. – ale Apr 24 '12 at 22:14
  • Agreed... the answer is no. I appreciate your efforts in trying to add some insight to this question, but why would you do all that work if you're calling cfdirectory anyway? That tag already returns only directories if you want it to. – Redtopia Apr 25 '12 at 05:00
3

Unfortunately, no. Unlike cfdirectory's type attribute, filters are only applied to the file/directory names. So I do not think it is possible to use filter to find directories only. Keep in mind you can always wrap cfdirectory in a function, then call it from your UDF. That is what the old DirectoryList function at cflib.org does.

the documentation is not clear on what can be filtered (except for *.txt).

You can only search the name. filter supports partial patterns (like find files containing "xxx"), searching by file extensions, or you could apply multiple patterns by using "|":

*test*        // partial pattern. names containing the word "test"
*.xls         // find Excel files
*test*|*.xls  // find names containing "test" OR Excel files

However, since the pattern is only applied to the name, it cannot be used to reliably identify directories.

Leigh
  • 28,765
  • 10
  • 55
  • 103
  • 1
    Just FYI: there is a feature req with Adobe to get this sorted out: https://bugbase.adobe.com/index.cfm?event=bug&id=3039908. It might be worth voting for, to get some traction behind it (although it's already missed the CF10 boat :-( – Adam Cameron Apr 22 '12 at 11:16
1

Leigh's answer is the correct one (as usual :) but I thought I'd throw in this code as a dead easy work around.

<cfdirectory directory="c:\blah" name="myDirQuery" action="LIST"/>

<Cfquery name="myDirQuery" dbtype="query">
  SELECT * FROM myDirQuery where type = 'dir'
</cfquery>

You could wrap it in your own function pretty easily. This gets you what you want in spite of the limitations of filtering.

Mark A Kruger
  • 7,183
  • 20
  • 21
  • er.... yes indeed. Sorry I missed that - all credit to you. I'll vote up your answer :) – Mark A Kruger Apr 24 '12 at 00:01
  • The point was to replace cfdirectory with DirectoryList b/c I was in a cfscript block. And if you are using cfdirectory, you don't need to do the extra work to filter directories because it allows you to get them with the "type" attribute. – Redtopia Apr 24 '12 at 13:48
1

I've used this in the past.

var = dirList(directory_path, false, "query")

// var is now a query record
dirArray = []; // create an array

for(i = 1;i LTE var.recordcount; i++){ 
   if(var.type[i] IS "dir") dirArray.append(var.name[i]);
}
SOS
  • 6,430
  • 2
  • 11
  • 29
ShangHugh
  • 13
  • 3
  • 1
    `var` is maybe the worst variable name you could possibly choose due to it's special meaning inside of .cfc methods. – timbrown Mar 21 '19 at 17:36
1

It's now possible to filter directories by name, as of CF11. That version enhanced DirectoryList() to add support for the "type" attribute. For example, to search for directory names containing "docs":

CF2018+ (using named parameters)

result = DirectoryList(path="c:\path",filter="*docs*", type="dir");

CF2016 and earlier

result = DirectoryList("c:\path", false, "query", "*docs*", "asc", "dir" );
SOS
  • 6,430
  • 2
  • 11
  • 29