Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Directory Lisitng using Foxpro 8 1

Status
Not open for further replies.
Apr 25, 2002
156
0
0
GB
Hi,

I want to get a list of all the *.Bak files that reside on our Network.

We have a Network Share called F:\ and i want to scan it and store the imformation to a text file.

On this drive there is hundred of directory with subdirectory inside and i am wanting to scan all the directories and capture all information as to what the file is called and the byte size

Our Server is running 2003

I guess if i wanted to use a freeware program i could do this but i wish to use my fox skills

I have tried with Adir() and also List Files but i can only get to the initial folder and it wont scan any subfolers

Any help gratefully received

rdrunner
 
I think that using adir only gives you the current directory and not the sub directories as well. I have used this before if you're happy to send the result to a file and then pick it up from there :

RUN "dir f:\*.bak /s > bakfiles.txt"

It will flash a black 'DOS box' so it's not elegant, but shellexecute didn't seem to work. You can then open the txt file and read the contents.

David Durnall
 

Rdrunner,

It's not clear what your end goal is. Is it to get a list of directories so that you can scan them for BAK files, or do you simply want a list of all the BAK files?

If the latter, you can do something like this:

Code:
RUN CMD /Cdir f:\*.bak /s >bakfiles.txt

That will give you all the filenames in a text file, along with each file's datetime stamp and size. You will have to parse out any lines containing "Directory of xxx" and "X File(s) XXX bytes", but that shouldn't be too difficult.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

My Visual FoxPro site: www.ml-consult.co.uk
 
Geoff

You have to be a little careful with recursion in VFP, there can be stack/nesting issues when you recurse more that 15-16 levels.

I've just thrown together the scruffiest bit of code on the planet - that will do the job in VFP native code, without using recursion.

Code:
PRIVATE MYTOPLEVEL,I,X,MYPATH,NUMFILES,NUMDIR,MYMASK
* WHERE TO START LOOKING
MYTOPLEVEL = "D:\DEV\"
* WHAT TO LOOK FOR
MYMASK = "*.BAK"

SET SAFETY OFF
CLOSE ALL
CLEAR
** CREATE A COUPLE OF TEMPORARY TABLES - ONE FOR THE FINAL FILENAME LIST (COMPLETE WITH PATHS
SELECT 0
CREATE TABLE C:\TEMP\FILELIST FREE (FPATH C(200) NOT NULL, FULLNAME C(200) NOT NULL, FILESIZE N(12,0) NOT NULL, FILEDATE D NOT NULL, FILETIME C(7) NOT NULL, FILEATTR C(20) NOT NULL)
** AND ONE FOR THE FOLDERS TO SEARCH
SELECT 0
CREATE TABLE C:\TEMP\DIRLIST FREE (FPATH C(200) NOT NULL,PROCESSED C(1) NOT NULL)
** USE AN INDEX TO KEEP CHECKING FOR UNPROCESSED SUBFOLDERS
INDEX ON PROCESSED TAG DIRLIST

** START BY PUTTING THE 'WHERE TO START' IN LIST OF UNPROCESSED FOLDERS
SELECT DIRLIST
SET ORDER TO DIRLIST
APPEND BLANK
REPLACE FPATH WITH MYTOPLEVEL
REPLACE PROCESSED WITH "N"
GO TOP

SELECT DIRLIST
SET ORDER TO DIRLIST
SEEK "N"
** SCAN THE LIST OF SUBFOLDERS - LOOKING FOR UNPROCESSED ONES
DO WHILE .NOT. EOF()
	** MAKE A NOTE OF THE FOLDERS PATH
	MYPATH = ALLTRIM(FPATH)+IIF(RIGHT(ALLTRIM(FPATH),1)<> "\","\","")
	** CHECK FOR FILES MATCHING MASK
	NUMFILES = ADIR(FLIST,MYPATH+MYMASK)
	FOR I = 1 TO NUMFILES
		** IGNORE THE . AND .. ONES
		IF FLIST[i,1] <> "." .AND. FLIST[i,1] <> ".."
			** STICK THE FILES IN THE FILE LIST
			SELECT FILELIST
			APPEND BLANK
			REPLACE FPATH 	 WITH MYPATH
			REPLACE FULLNAME WITH FLIST[i,1]
			REPLACE FILESIZE WITH FLIST[i,2]
			REPLACE FILEDATE WITH FLIST[i,3]
			REPLACE FILETIME WITH FLIST[i,4]
			REPLACE FILEATTR WITH FLIST[i,5]
		ENDIF
	NEXT
	** MARK THAT FOLDER AS PROCESSED
	SELECT DIRLIST
	REPLACE PROCESSED WITH "Y"
	** NOW CHECK THE FOLDER FOR SUBFOLDERS - HAVE TO DO THIS BECAUSE THE MASK 
	** FOR FILES OF INTEREST WILL BE DIFFERENT TO THE ONE FOR FOLDERS
	NUMDIR = ADIR(ALIST,MYPATH+"*.*","D")
	** FOR EACH FOLDER FOUND
	FOR I = 1 TO NUMDIR
		** IGNORE THE ONES THAT ARE NOT FOLDERS AND THAT ARE CALLED . OR ..
		IF "D"$ALIST[i,5] .AND. ALIST[i,1] <> "." .AND. ALIST[i,1] <> ".."
			SELECT DIRLIST
			APPEND BLANK
			REPLACE FPATH WITH MYPATH+ALIST[i,1]
			REPLACE PROCESSED WITH "N"
		ENDIF
	NEXT
	** LOOK FOR THE NEXT UNPROCESSED FOLDER
	SELECT DIRLIST
	SET ORDER TO DIRLIST
	SEEK "N"
ENDDO

SELECT FILELIST
GO TOP
BROWSE

Regards

Griff
Keep [Smile]ing
 
I've polished the code for the above up and submitted it as a FAQ.

If the nice TT people accept it I'll point you to it.



Regards

Griff
Keep [Smile]ing
 
Hi Griff

That does exactly what i am looking for it to do ... now i am wanting to delete each file given certain date and file size paramaters as well.

These i think i am able to work out.

The only thing i would need to do is if the file is extremley large will i need to put some sort of wait window in to allow it to delete the file before moving on to the next file.

Some of the BAK files i have foun are in excess of 500mb and i want to be able to delete these.

regards

rdrunner
 
Rdrunner,

Very pleased to be of help, I'm using the new routine myself - just added it to a product!

One extra tip for you, the FILETIME field should be 8 characters!

Thanks for the star

Regards

Griff
Keep [Smile]ing
 
Hi Mike,

What I have done is pretty much that, a UDF that takes four parameters;

1) place to start looking
2) pattern to look for
3) temporary folder name
4) whether or not to show progress (via a wait window)

It returns the name of the created table of file names, sizes, dates, times and attributes

Hopefully it'll pop-up on the FAQs later

It would be easy to add the other filters yourself then - either in a modified UDF or using the resultant table.

Thanks for the kind words though!



Regards

Griff
Keep [Smile]ing
 
Take a look at thread184-1200449. I used it to build a backup routine.

Code:
SET DEFAULT TO JUSTPATH(SYS(16))

IF !FILE([prg_backup.dbf])
	CREATE TABLE prg_backup (UpdateDt t, FullName c(200), PrgTxt m, PrgLen n(6))
	INDEX ON UPPER(FullName) TAG a
ELSE
	USE prg_backup 
	SET ORDER TO 1
ENDIF 

lnseconds=seconds()
	UpdateTargets([C:\], [*.prg])
	Eval_and_BackUp()
?SECONDS()-lnSeconds

BROWSE NOWAIT 
RETURN 

PROCEDURE UpdateTargets(lcPath, lcFileName)
LOCAL lnFolders, lnFiles, lnFor
LOCAL ARRAY laFolder[1], laFiles[1]

   lcPath  = ADDBS(lcPath)
   lnFolders = ADIR(laFolder,lcPath+[*.*],[D])
   FOR lnFor = 1 TO lnFolders 
       IF LEFT(laFolder[m.lnFor,1],1)==[.]=.f. AND [D]$laFolder[lnFor,5]=.t. AND UPPER(laFolder[lnFor,1])==[TEMP]=.f. ;
       		AND [PROGRAM FILES]$UPPER(laFolder[lnFor,1])=.f. and [DOCUMENTS AND SETTINGS]$UPPER(laFolder[lnFor,1])=.f.
        	  UpdateTargets(lcPath+laFolder[lnFor,1],lcFileName)
       ENDIF
   NEXT
   
   lnFiles = ADIR(laFiles,lcPath+lcFileName)
   FOR lnFor = 1 TO lnFiles 
       IF LEFT(laFiles[m.lnFor,1],1)==[.]=.f. AND [D]$laFiles[m.lnFor,5]=.f.
          SEEK(UPPER(lcPath+laFiles[lnFor,1]))
          IF EOF()
          	INSERT INTO prg_backup VALUES (DATETIME(), UPPER(lcPath+laFiles[lnFor,1]), [], -1)
          ENDIF 
       ENDIF
   NEXT
RETURN []
ENDPROC    
   
PROCEDURE Eval_and_BackUp
	lnNewPrgsFound=0
	lnPrgsUpdated=0
	lnPrgsUnchanged=0

   SELECT prg_backup 
   SCAN 
   	lcPrgPath=ALLTRIM(FullName)
   	lcPrgTxt=FILETOSTR(lcPrgPath)
   	lcOldPrg = PrgTxt
	
   	DO CASE 
   		CASE lcOldPrg = lcPrgTxt
			lnPrgsUnchanged = lnPrgsUnchanged + 1
		
		CASE EMPTY(lcOldPrg)
			lnNewPrgsFound = lnNewPrgsFound + 1
	    	REPLACE UpdateDt WITH DATETIME(), PrgTxt WITH lcPrgTxt, PrgLen WITH LEN(ALLTRIM(lcPrgTxt))
	
		CASE lcOldPrg # lcPrgTxt
			lnPrgsUpdated = lnPrgsUpdated + 1
			REPLACE UpdateDt WITH DATETIME(), PrgTxt WITH lcPrgTxt, PrgLen WITH LEN(ALLTRIM(lcPrgTxt))
		ENDCASE 
ENDSCAN 

	messagebox(TRANSFORM(lnPrgsUnchanged)+[ Unchanged Programs found.]+ CHR(13)+CHR(10)+;
			TRANSFORM(lnNewPrgsFound)+[ New Programs found and backed up.]+ CHR(13)+CHR(10)+;
			TRANSFORM(lnPrgsUpdated)+[ Known Programs found and updated.])
ENDPROC
 
You have to be a little careful with recursion in VFP, there can be stack/nesting issues when you recurse more that 15-16 levels.

Good point. I've never hit it myself in my own directory tree but if you're looking somewhere like [TT]C:\Documents and Settings\grf\Application Data\Microsoft\ ...[/TT] then I could well imagine running out of stack before you reached the bottom (or is it the top) of the tree.

Geoff Franklin
 
You also have to think about where you're calling the recursion from, you could be four or five levels down to start with.

I found it trying to calculate factorials in Clipper initially - which are generally done using recursion - but found it was only good for relatively small numbers.





Regards

Griff
Keep [Smile]ing
 
An API Version

usage : do dirtree with 'Directory','FileMask'
eg: : do diretree with 'c:\temp','*.bak'

Code:
procedure dirtree
PARAMETERS cDir,cExt

DO declare

LOCAL loDir
loDir = CreateObject("Tdir", cDir)
GO TOP

browse

***Code to do whatever you want with the files

DEFINE CLASS Tdir As Custom
cursorname=""
treelevel=0
cExt=UPPER(Cext)

PROCEDURE Init(lcPath, loParent)
    IF TYPE("loParent")="O"
        THIS.cursorname = loParent.cursorname
        THIS.treelevel = loParent.treelevel + 1
    ELSE
        THIS.cursorname = "cs" + SUBSTR(SYS(2015), 3,10)

        SELECT 0
        CREATE CURSOR (THIS.cursorname) (treelevel N(3),;
            filesize N(12), date D, fullname C(250))

    ENDIF

    THIS.DoFind(lcPath)

PROCEDURE DoFind(lcPath)
#DEFINE MAX_PATH 260
#DEFINE FILE_ATTRIBUTE_DIRECTORY 16
#DEFINE INVALID_HANDLE_VALUE -1
#DEFINE MAX_DWORD 0xffffffff+1
#DEFINE FIND_DATA_SIZE  318

    lcPath = ALLTRIM(lcPath)
    IF Right(lcPath,1) <> "\"
        lcPath = lcPath + "\"
    ENDIF

    LOCAL hFind, cFindBuffer, lnAttr, cFilename, nFileCount,;
        nDirCount, nFileSize, cWriteTime, nLatestWriteTime, oNext

    cFindBuffer = Repli(Chr(0), FIND_DATA_SIZE)
    hFind = FindFirstFile(lcPath + "*.*", @cFindBuffer)
    IF hFind = INVALID_HANDLE_VALUE
        RETURN
    ENDIF
    
    STORE 0 TO nDirCount, nFileCount, nFileSize, nLatestWriteTime
    DO WHILE .T.
        lnAttr = buf2dword(SUBSTR(cFindBuffer, 1,4))
        cFilename = SUBSTR(cFindBuffer, 45,MAX_PATH)
        cFilename = Left(cFilename, AT(Chr(0),cFilename)-1)

        cWriteTime = SUBSTR(cFindBuffer, 21,8)
        IF EMPTY(nLatestWriteTime)
            nLatestWriteTime = cWriteTime
        ELSE
            IF CompareFileTime(cWriteTime, nLatestWriteTime) = 1
                nLatestWriteTime = cWriteTime
            ENDIF
        ENDIF

        IF BITAND(lnAttr, FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY
        * for a directory
            IF Not LEFT(cFilename,1)="."
                oNext = CreateObject("Tdir", lcPath + cFilename + "\", THIS)
            ENDIF
        ELSE
        * for a regular file
            IF LIKE(cExt,cFilename) 
               nFileSize = nFileSize +;
                  buf2dword(SUBSTR(cFindBuffer, 29,4)) * MAX_DWORD +;
                  buf2dword(SUBSTR(cFindBuffer, 33,4))
               ntime=sys2dt(nLatestWriteTime)
               INSERT INTO (THIS.cursorname) VALUES (THIS.treelevel,;
                m.nFileSize,m.ntime,lcPath+cFileName)

            endif 
        ENDIF

        IF FindNextFile(hFind, @cFindBuffer) = 0
            EXIT
        ENDIF
    ENDDO
    = FindClose(hFind)
ENDDEFINE

FUNCTION sys2dt(lcFiletime)
* converts a SYSTEMTIME buffer to DATE
    LOCAL lcSystime, lcStoredSet, lcDate, lcTime, ltResult,;
        lnYear, lnMonth, lnDay, lnHours, lnMinutes, lnSeconds

    lcSystime = Repli(Chr(0), 16)
    = FileTimeToSystemTime(lcFiletime, @lcSystime)

    lnYear = buf2word(SUBSTR(lcSystime, 1,2))
    lnMonth = buf2word(SUBSTR(lcSystime, 3,2))
    lnDay = buf2word(SUBSTR(lcSystime, 7,2))
    lnHours = buf2word(SUBSTR(lcSystime, 9,2))
    lnMinutes = buf2word(SUBSTR(lcSystime, 11,2))
    lnSeconds = buf2word(SUBSTR(lcSystime, 13,2))
    
    lcStoredSet  = SET("DATE")  
    lcStoredSet1 = SET('STRICTDATE')
    SET DATE TO MDY  
    SET STRICTDATE TO 0
    lcDate = STRTRAN(STR(lnMonth,2) + "/" + STR(lnDay,2) +;
        "/" + STR(lnYear,4), " ","0")  

     ltresult=CTOT(lcdate)
    SET DATE TO &lcStoredSet
    SET STRICTDATE TO &lcStoredset1
      
RETURN  ltResult

FUNCTION buf2word(lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) +;
    Asc(SUBSTR(lcBuffer, 2,1)) * 256

FUNCTION buf2dword(lcBuffer)
RETURN Asc(SUBSTR(lcBuffer, 1,1)) +;
    Asc(SUBSTR(lcBuffer, 2,1)) * 256 +;
    Asc(SUBSTR(lcBuffer, 3,1)) * 65536 +;
    Asc(SUBSTR(lcBuffer, 4,1)) * 16777216

PROCEDURE declare
    DECLARE INTEGER FindClose IN kernel32 INTEGER hFindFile

    DECLARE INTEGER FindFirstFile IN kernel32;
        STRING lpFileName, STRING @lpFindFileData

    DECLARE INTEGER FindNextFile IN kernel32;
        INTEGER hFindFile, STRING @lpFindFileData

    DECLARE INTEGER FileTimeToSystemTime IN kernel32;
        STRING lpFileTime, STRING @lpSystemTime

    DECLARE INTEGER CompareFileTime IN kernel32;
        STRING lpFileTime1, STRING lpFileTime2

***Modified from VFP API code on news2news.com


 
Mike,

I've modified the code in the FAQ to bring it closer to your suggestion - returning the name of the cursor file, but allowing the user to leave it open as the current work area if they like.



Regards

Griff
Keep [Smile]ing
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top