Announcement

Collapse
No announcement yet.

Rmdir

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Rmdir

    I want to be able to delete a directory and all its subdirectories and files in a large variable set of files..

    RMDIR requires that you delete all the files and the directories in any directory before it works. This means that you have to ascertain what directories that you have and then RMDIR from the bottom and move upwards.

    The discussion on this forum seems to recognise this problem. There are some Windows solutions listed but a) I do not understand them and b) apparently they are dependent on Windows versions and maybe even PB versions. My version is theoretically not dependent on Windows differences.

    So I decided to write a routine which deleted everything in a directory and all its sub directories and sub sub directories.

    It has been fun

    The program here makes a list (an 'array' in fact) of all the directories including and under any named directory.

    The logic breakthrough came when I divorced the 'delete' from the 'listing'. List first then delete afterwards. And the reult is quite fast enough although it can probably be sped up.

    I had some fun issues.

    The DIR$ instruction only gives the name of the directory - not the path. Have I got that right? So you have to add the path. This means that you have to change directories to the directories that you are dealing with.

    I do not know how to REDIM an array if it gets too big without losing data. So you have to set the array size high - or whatever. Is there a way of increasing the size as we go? I considered setting a lower number and restarting with a higher number (etc etc) but that was a bit clumsy.

    The program as delivered here merely prints out all the found directories. The practical uses are:

    1 You can use the list (the array) of directories to find a file (or multiple copies of a file). You can just FOR NEXT through the array.

    2 You can use the list (the array) to delete all the directories and their files from a named directory down. BUT you have to start from the bottom up so that you are clearing out the lower directories first. For each directory, you have to do a KILL "*.*" and then a RMDIR

    I have 42446 directories on my main drive - do you know how many you have? Just run the program with start_dir = "C:" and you will know

    When using start_dir = "C:" a peculiar thing is that about halfway through - at directory number 22651 in fact, the program stops and thinks for about 28 seconds (unscientific timing, done on my fingers!). No apparent reason. It is in the middle of the Windows directories. There are some odd named directories there and I wondered if that was an issue. I have a solid drive disk and I also wondered if this was doing something to cause this.

    I acknowledge that I should use DO LOOPS but I could not make them work and anyway, they would not save much time or add to clarity.

    Here is the program.

    Code:
    #COMPILE EXE
    #DIM ALL
    GLOBAL start_dir AS STRING
    GLOBAL list_of_directories() AS STRING
    GLOBAL count_of_directories AS LONG
    GLOBAL loop_count AS LONG
    GLOBAL start_of_loop_switch AS LONG
    GLOBAL max_number_of_directories AS LONG
    GLOBAL this_directory AS STRING
    GLOBAL just_found_directory AS STRING
    
    FUNCTION PBMAIN () AS LONG
    max_number_of_directories = 100000  'has to be manually set
    'choose one or set your own directory
    start_dir = CURDIR$             '}  Runs from where program is
    start_dir = "C:\"                      '}  Does the whole disk
    start_dir = "C:\File2019\"       '}  One of my operational directories
    CHDIR start_dir
    DIM list_of_directories(1 TO max_number_of_directories) AS STRING
    count_of_directories = 1
    list_of_directories(1)= start_dir
    loop_count = 0
    'main loop   ******************************
    start_of_loop:
    start_of_loop_switch = 0
    INCR loop_count
    IF loop_count >  max_number_of_directories THEN
        PRINT "Too many directories"
        WAITKEY$
        END IF
    this_directory = list_of_directories(loop_count)
    IF LEN(this_directory) = 0 THEN GOTO dirdone
    CHDIR list_of_directories(loop_count)
    DIR$ CLOSE
    this_directory_loop:
    'this_directory_loop:********************
    IF start_of_loop_switch = 0  THEN
        start_of_loop_switch = 1
        just_found_directory =DIR$(this_directory+"\*.*",ONLY 16)
    ELSE
        just_found_directory =DIR$
    END IF
    IF LEN(just_found_directory) <> 0 THEN
        INCR count_of_directories
        list_of_directories(count_of_directories)=  CURDIR$+"\"+just_found_directory
         ' PRINT count_of_directories; :print list_of_directories(count_of_directories) this line is just for fun
        GOTO this_directory_loop
    END IF
    GOTO start_of_loop
    'end of directory loop***********************
    dirdone:
    'end of main loop  ********************
    'At this point here, you probably want to do something else with your list than printing it out!
    FOR loop_count = 1 TO count_of_directories
        PRINT loop_count;
        PRINT  list_of_directories(loop_count)
        NEXT
    WAITKEY$
    END FUNCTION
    Looking forward to your comments.
    [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
    Kerry Farmer

  • #2
    "RMDIR requires that you delete all the files and the directories in any directory before it works. This means that you have to ascertain what directories that you have and then RMDIR from the bottom and move upwards."

    RD drive:/directory /S (optional /Q) should do the trick)

    Windows XP and later syntax

    RMDIR [/S] [/Q] [drive:]path
    RD [/S] [/Q] [drive:]path

    /S Removes all directories and files in the specified directory in addition to the directory itself. It is used to remove a directory tree.
    /Q Quiet mode, do not ask if ok to remove a directory tree with /S.

    /Mikael

    Comment


    • #3
      Code:
      'Kerry
      '... some code
      local list_of_directories() as string
      max_number_of_directories = 10000
      dim list_of_directories(max_number_of_directories)
        'I left out "1 to" from the "dim" code line.
        'Yes, it creates a zeroith indexed member in the
        'array, BUT NOONE SAYS YOU MUST USE IT, and it
        'makes more efficient code, continue to start with
        'index 1 in your other code.
      '  
      '... some code later you detect you need a larger array
      redim preserve list_of_directories(ubound(list_of_directories()) + 1000)
        the key word "preserve" prevents loss of existing array data
      '  this can be repeated if you run-out again
       'suggest you use another long variable to track the last array
        'member used. Use that to avoid using empty members for
        'deleting dirs/files.
      Cheers,

      ((Help has pretty good notes on PRESERVE in the REDIM entry ))
      Dale

      Comment


      • #4
        Kerry,
        here's one I wrote years ago.
        It's recursive.
        It creates a .csv file called "c:\FileList.csv" listing all the files on the drive.

        On my 10 year old PC it creates the list of my 41,718 folders containing 1,028,932 files in 34s on a SSD drive.

        It does my other, non-SSD, disk in 1m55s with 440,810 files and 23,065 folders.

        Code:
        PBCC6 program
        'list all files on a drive or in a folder to a text file on disk that can be opened in Excel.
        
        #COMPILE EXE
        #DIM ALL
        #BREAK ON
        
        #INCLUDE "win32api.inc"
        
        
        GLOBAL gFilesCopied AS LONG
        GLOBAL gDirectoriesCopied AS LONG
        GLOBAL hFile             AS LONG
        
        
        FUNCTION PBMAIN () AS LONG
        
        LOCAL StartDirectory  AS STRING
        
        INPUT "Start at which folder? (e.g c:\ or d:\ThisFolder\)";StartDirectory
        
        IF RIGHT$(StartDirectory,1) <> "\" AND RIGHT$(StartDirectory,1) <> "/" THEN
            StartDirectory += "\"
        
        END IF
        
        hFile = FREEFILE
        OPEN "c:\FileList.csv" FOR OUTPUT AS #hFile
        
        
        PRINT#hFile, "Started at " TIME$;" ";DATE$
        
        PRINT#hFile, RecursiveFileList(StartDirectory)
        
        PRINT#hFile,
        PRINT#hFile, "Finished at " TIME$;" ";DATE$
        PRINT#hFile,
        PRINT#hFile, "Files found =";gFilesCopied
        PRINT#hFile, "Directories found =";gDirectoriesCopied
        
        PRINT#hFile, "On exit:";ERROR$
        
        CLOSE#hFile
        
        BEEP
        PRINT "Press key to end"
        WAITKEY$
        
        END FUNCTION
        
        
        
        FUNCTION RecursiveFileList(StartFolderName AS STRING) AS LONG
        
        LOCAL FileData  AS WIN32_FIND_DATA
        LOCAL hFindFile AS LONG
        LOCAL NextFile  AS ASCIIZ * %MAX_PATH
        LOCAL FileCount AS LONG
        LOCAL temp AS LONG
        LOCAL NextFromFolderName AS STRING
        
        
        NextFile = StartFolderName + "*.*"
        
        hFindFile = FindFirstFile(NextFile,FileData)
        
        IF hFindFile <> %INVALID_HANDLE_VALUE THEN
            DO
                'we found a file or directory
                NextFile = StartFolderName + FileData.cFileName
        
                IF (FileData.dwFileAttributes AND %FILE_ATTRIBUTE_DIRECTORY) = 0 THEN
                    'it's a file
                    PRINT#hFile, NextFile, ",",FileData.nFileSizeLow
                    INCR gFilesCopied
        
                ELSE
                    'it's a directory
                    IF (FileData.cFileName <> ".") AND (FileData.cFileName <> "..") THEN
                    'it's not the current or parent directory, so search it recursively
                        NextFromFolderName = StartFolderName + FileData.cFileName
        
                        INCR gDirectoriesCopied
        
                        temp = RecursiveFileList(NextFromFolderName+"\")
        
                        FileCount =  temp + FileCount
        
                    END IF
        
                END IF
        
            LOOP WHILE FindNextFile(hFindFile,FileData)
        
            FindClose(hFindFile)
        
        END IF
        
        FUNCTION = FileCount
        
        END FUNCTION

        Comment


        • #5
          Or...
          Code:
          LOCAL shFileOp        AS SHFILEOPSTRUCT
          LOCAL sFolderToDelete AS STRING
          LOCAL RetVal          AS LONG
          
          sFolderToDelete = "Z:\FolderToDelete" & $NUL & $NUL 'Full path double-null terminated
          shFileOp.hwnd   = hDlg
          shFileOp.wFunc  = %FO_DELETE
          shFileOp.pFrom  = STRPTR(sFolderToDelete) 'Full path double-null terminated
          shFileOp.pTo    = 0
          shFileOp.fFlags = %FOF_NOCONFIRMATION OR %FOF_SILENT OR %FOF_ALLOWUNDO OR %FOF_NOERRORUI 'OR %FOF_NORECURSION
          RetVal          = SHFileOperation(shFileOp)

          Comment


          • #6
            Kerry,
            your code gives a different result to mine.
            Try selecting all the files in the folder in Windows, right click on them then choose "properties" and that'll return the number of files and folders.
            Then compare it with the same folder using your program.

            Paul.


            Comment


            • #7
              Thanks everyone

              Oops - I did not read the PRESERVE stuff - obvious advantage here

              It takes 38 seconds - not sure if that includes the 28 second delay or not - need to do some more work. Maybe that delay is to do with the display and not the actual routine as such. (Solid state disk)

              Excuse me Pierre - but does your code do a full delete? In a perfect world how could I have known about that?

              Kerry

              [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
              Kerry Farmer

              Comment


              • #8
                Paul

                Oops we crossed.

                I tried to do that for my smaller directory laden file - and got the same answer as my program.

                I will do the Windows thing tomorrow - it is 3am here.
                [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
                Kerry Farmer

                Comment


                • #9
                  Excuse me Pierre - but does your code do a full delete?
                  Yep, since Windows 95. You even have the option to allow undo or not and more...

                  In a perfect world how could I have known about that?
                  A way I often use is via Microsoft web site, like...
                  Google with "Windows api delete a folder" give "RemoveDirectory"
                  with a remark that say "To recursively delete the files in a directory, use the SHFileOperation function."

                  Comment


                  • #10
                    Kerry,
                    the difference might be to do with hidden folders not being included.

                    Comment


                    • #11
                      .Paul

                      You are absolutely right

                      The program says 35,593 folders and the Properties says 7261 folders on my machine (Windows 10 - no funny stuff)

                      Hmmm

                      Some thoughts:

                      1 The figures are correct and consistent for my normal folders. One folder which has several layers of folders shows 59 in both plaves and I have carefully checked and ticked them off.

                      2 The DIR$ qualifier that I use is 16 for 'folders'. I have not added on the '2' for hidden which means that I should not be picking up hidden folders (I will do that soon) So the difference is the wrong way round!!!!

                      3 I do not intend to use my program in the Windows folders - so it does not matter - except we should try and understand maybe for our own satisfaction

                      4 I still have no explanation for my 'lost' 28 seconds - so maybe that is part of the story

                      Kerry


                      PS If I make the DIR$ qualifier 18 ie include hidden files, I get 35610 in the Windows folder with my program. Implying that there are 17 hidden folders.
                      Last edited by Kerry Farmer; 25 Aug 2019, 03:35 PM. Reason: added ps
                      [I]I made a coding error once - but fortunately I fixed it before anyone noticed[/I]
                      Kerry Farmer

                      Comment


                      • #12
                        Originally posted by Kerry Farmer View Post

                        PS If I make the DIR$ qualifier 18 ie include hidden files, I get 35610 in the Windows folder with my program. Implying that there are 17 hidden folders.
                        Don't forget "system" files/folders:

                        %SUBDIR OR %SYSTEM of %HIDDEN = 22

                        Comment


                        • #13
                          There is a problem with Paul's code in Post #4 using %MAXPATH in deeply nested directories.

                          Please see this thread:
                          https://forum.powerbasic.com/forum/u...recursive-code

                          Comment

                          Working...
                          X