Re: Could this be faster?
- Posted by petelomax at fastmail.fm Dec 15, 2005
- 567 views
I though I'd try walk_dir using the windows API. This appears to be about 3 times faster, YMMV. It uses arwen, though it should be relatively trivial to change the constants to conform to win32lib.
include arwen.ew constant -- Define FINDDATA Structure FINDDATA = new_struct(), FINDDATA_dwAttr = struc(C_LONG), FINDDATA_Times3 = struc(anySize(24)), FINDDATA_nFileSizeHigh = struc(C_LONG), FINDDATA_nFileSizeLow = struc(C_LONG), FINDDATA_res2 = struc(anySize(8)), FINDDATA_cFileName = struc(anySize(260)), FINDDATA_cAltFileName = struc(anySize(14)), fd = allocate(sizeof(FINDDATA)), xFindFirstFile = link_c_func(kernel32, "FindFirstFileA", {C_POINTER, -- LPCTSTR lpFileName, // address of name of file to search for C_POINTER},-- LPWIN32_FIND_DATA lpFindFileData // address of returned information C_LONG), -- HANDLE xFindNextFile = link_c_func(kernel32, "FindNextFileA", {C_POINTER, -- HANDLE hFindFile, // handle of search C_POINTER},-- LPWIN32_FIND_DATA lpFindFileData // address of structure for data on found file C_INT), -- BOOL xFindClose = link_c_func(kernel32, "FindClose", {C_POINTER},-- HANDLE hFindFile // file search handle C_INT), -- BOOL INVALID_HANDLE_VALUE=-1 function get_file_ext(sequence filename) integer c for i=length(filename) to 1 by -1 do c = filename[i] if c = '.' then return filename[i+1..length(filename)] elsif c>='A' and c<='Z' then filename[i] = c+32 end if end for return "" end function procedure wd(sequence path) -- walk_dir coded using winAPI direct. -- results not in any particular order. integer d atom fH, attr sequence longname sequence ipath sequence dirstack ipath = path dirstack={} if platform()!=2 then ?9/0 end if --Win32 only supported while 1 do -- -- Force consistent use of '\\' vs '/'. -- d=find('/',path) if d=0 then exit end if path[d]='\\' end while fH=INVALID_HANDLE_VALUE if length(path) and path[length(path)]='\\' then path&="*.*" elsif length(path) and path[length(path)]=':' then ipath = path&'\\' path&="\\*.*" --NB I doubt this will work with wildcards! elsif not find('*',path) and not find('?',path) then -- -- Check if the passed path is a directory; -- if it is, list it's contents, not just it. -- fH = c_func(xFindFirstFile,{allocate_StringZ(path),fd}) if fH!=INVALID_HANDLE_VALUE then attr = peek4u(fd + FINDDATA_dwAttr) if and_bits(attr,#10) then -- directory bit ipath&='\\' path&="\\*.*" if c_func(xFindClose,{fH}) then end if fH=INVALID_HANDLE_VALUE end if end if end if if fH=INVALID_HANDLE_VALUE then fH = c_func(xFindFirstFile,{allocate_StringZ(path),fd}) end if if fH!=INVALID_HANDLE_VALUE then while 1 do attr = peek4u(fd + FINDDATA_dwAttr) longname = peek_string(fd + FINDDATA_cFileName) if and_bits(attr,#10) then if not find(longname,{".",".."}) then dirstack = append(dirstack,ipath&longname) end if else if find(get_file_ext(longname),{"aac","mp4", "mp3", "mp2", "mp1", "ogg", "wav"}) then -- DEV: call external routine/append to result stack puts(1,longname&'\n') end if end if if not c_func(xFindNextFile,{fH,fd}) then exit end if end while if c_func(xFindClose,{fH}) then end if for i=1 to length(dirstack) do wd(dirstack[i]) end for end if end procedure wd("C:\\")
Regards, Pete -- petelomax at fastmail.fm -- http://www.fastmail.fm - Access your email from home and the web