Copy Folder Test

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]

 

 

Search

Search WWW

Search DelphiForFun.org

As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.

 

Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 

     

We receive a few cents from each purchase.  Thanks

 


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa® Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa® 365 Puzzlers  Calendar 2017

Mensa® 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)

Contact

Feedback:  Send an e-mail with your comments about this program (or anything else).

Search DelphiForFun.org only

 

 

 

Problem Description

Required: A program to copy all of the files matching a file mask to a different folder. 

Background & Techniques

I recently had need for a procedure to copy all files in a CD folder  to a new folder on a hard disk drive and reset the "ReadOnly" attributes.   . 

This program was written to test the resulting new  "CopyFolder" function, but it seems that the program has enough features to perhaps serve as a useful utility for non-programmers..

Usage is straight-forward: Select an input folder and an output folder.  The output folder may be existing or a new one.  Other options include:

bulletSet a file mask to control which files get selected.  A separate "file masks" page defines masking string options and provides a few examples.
bulletSet the scope of the operations  - files in the input folder only or input folder plus all files in folders contained within the input folder.
bulletWhether to retain or reset the  "readonly" attribute on the copied files.
bulletHow to handle duplicate files, i.e. files already existing in the target folder.  options are
bulletIgnore the file, do not copy.
bulletCopy the file, replacing the existing file in the the target folder.
bulletCopy the file only if the source file is newer than the target.
bulletAsk the user whether to overwrite the existing target file.

Click the "Copy" button to complete the operation.  A list of files copied and the total count will be displayed when the operation has been completed.

You may interrupt the operation by clicking the "Stop" button but the copies of files already processed will remain in the output folder.  If you select "Ask" option for the Duplicate Files radio group, a reply of "Cancel" when asked will also stop the operation.
 

Non-programmers are welcome to read on, but may want to skip to the bottom of this page to download executable version of the program.

Notes for Programmers

The program calls the "CopyFolder" function contained in unit UCopyFolder.pas to do most of the work.   CopyFolder copies files matching a given mask from one folder to another. Parameters are;

bulletFromFolder: The path to the folder containing the files to be copied
bulletToFolder: The path to the folder to receiver the files
bulletMask: A file mask to control which files are selected ('*.*' = All files)
bulletDupFileOpts: Four numeric options are available when the file already exists:
bullet0 ==> skip the file
bullet1 ==> always copy the file
bullet2 ==> copy the file if it is newer than the existing copy
bullet3 ==> ask the user what action to take
bulletCopySubFolders: Files in subfolders of the specified FromPath folder will also be copied if this parameter is true.
bulletResetReadOnly: If true, input files marked as "Readonly" will have that attribute removed in the target location.
bulletFileExit: The address of optional method (function of object) specifying a user function to be called before each file is copied.  If the callback procedure is specified, it receives 4 parameters:
bulletInpath: Path to the input file.
bulletOutputPath: Path where the file will be copied.
bulletFilename: Name of the file to be copied.
bulletCancopy: Boolean parameter with a default value of true. Set "Cancopy" to false to skip copying this file.

FileExit should  return a result value of true if copying is to continue,  and false to abort the copy procedure without copying further files.

 

CopyFolder uses a few techniques worth describing for future reference

bulletRecursive search through a folder and subfolders is a technique we have used before but filtering files with a file mask makes the procedure a little more complicated.  The FindFirst function can filter returned records based on a specified file mask, but since we will likely be recursively calling CopyFolder  with subdirectories of the input directory, FindFirst must search all file names (with a file name mask of "*.*")
bulletFile mask matching - FindFirst and successive FindNext calls  retrieve file information in a TSearchrec for each call including the file name, date, attributes .  The Name field is passed to the MatchesMask function along with the user specified mask.  I could find no user oriented description of mask strings, so I added a tab sheet to the program with the mask  fields described and a few examples.  
bulletOverloading a function or procedure with an optional method call - I decided to provide an optional callback function passed as a parameter to CopyFolder.  The callback function is called for each file to be copied,  passing the parameters described above.  The typical way to make a parameter optional is to provide an overloaded version without the optional parameter  and from there call the "real" version with a default value for the missing parameter.  (Delphi recognizes the keyword "overload" in the procedure definition and will accept multiple definitions with the same name so long as the parameter lists are different.)  The tricky part here is that we cannot pass a "Nil" (no address) value for the callback function because the function is defined as a method type  function "of object" meaning that it is a method of an object.   Method type functions are passed as a pair of pointers, a pointer to the function code and a a pointer to the class instance to which it belongs.    I got around the problem by defining a DummyFileExit function within a TDummyClass definition.  And an instance if TDummyClass named DummyClass.  This DummyfFileExit may now be passed as the default FileExit for cases where the user chose not to provide one.  CopyFile checks and ignores any reference to DummyFileExit, so it is not necessary to actually create the DummyClass instance.   Whew!     
bulletChanging file attributes - I only way i could find to reset the ReadOnly attribute was to copy the (using the Windows CopyFile funtion) and then use the SetFileAttr function to reset the attribute if in was set in the input.

Addendum November 10, 2008:  At a user's request, a new option was added to Version 2 of Copy Folder Test.   It is now possible to ignore the folder structure  files from  sub-folders of the select input folder and to copy all files directly to the selected output folder.   Additionally counts of files copied,
duplicate files overwritten and duplicate files not copied are kept by the copy folder functions and are reported by this program at job completion time.  A final new option add "Yes to all" and "No to all" buttons to the Ask dialog to specify the default action to be taken when additional duplicate file names are encountered.

 December 4, 2008: Version 3 changes the file date check for the overwrite decision to use "Last modified date" instead of "Creation date".  Seems to make more sense that way as a user suggested.  I also fixed a bug that allowed the program to try to copy a destination folder which happened to be a subfolder of the source folder - not a good idea since it would loop forever, or at least until the disk filled up!   
 

July 15, 2012:  Version 3.1 was posted today with three enhancements:

bulletAn option to process files without actually copying them has been added.  This is to determine the total count and size of zipped files here on DFF.
bulletDirectories with the "System" attribute are now included in the directories list so that they can be selected.  "Web Site" folders are one example of types that previously were not selectable.  The fix required correcting  an "oversight" in the Delphi 7 FileCtrl unit which caused the TDirectoryListBox class to exclude these directories.  The modified FileCtrl unit is included in the source code download.
bullet A change to correctly report file sizes larger than 4GB previously included in our List Large Files utility program is now included here.  

May 11, 2013:  In the original program I envisioned performing operations like copying all files in folder "ProgramA" to a new folder "ProgrtamA_Test".   A viewer pointed out it did not work  well for his intended use: i.e. copy folders "ProgramA", "ProgramB", and "ProgramC" into a folder named "Backups".  In other words, copy the folder name as well as the files in that folder.  It seemed like a reasonable request to me, so Version 3.2 posted today adds a checkbox: "Include selected input folder record in output" to do just that.    

Running/Exploring the Program 

bullet Download source
bullet Download  executable

Suggestions for Further Explorations

 Is there a more direct way to make a method pointer an optional parameter in a function call?

 

Original Date: October 30 2006

Modified: May 11, 2018

 

  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright © 2000-2018, Gary Darby    All rights reserved.