?
Solved

Renaming folders and subfolders with a pattern

Posted on 2006-12-01
5
Medium Priority
?
384 Views
Last Modified: 2016-08-02
Hi,
I could use some help with the thinking on this one.

Suppose I wanted to rename all the folders and subfolders from some root according to a pattern.

For example, suppose I wanted to replace "*fred*" in each of the paths below with ALFREDO.

(To make life a little simpler, only replace the first occurrence in any segment so
\xfred2\yfreddofred\fred.htm would become
\xALFREDO2\yALFREDOdofred\fred.htm )

Now, I cannot use repeated findfirst/findnext loops because the replacement pattern could contain the patten to match.

It would be nice to do it in one pass, with some sort of recursive follow down the tree algorithm. But again, I don't see how because the Tsearchrec contents (after a rename) would be wrong.

There should be a simple way .. just can't see it for the moment. Maybe something to do with PIDL's?

Assume for the purposes of exposition that the folders to be renamed are

c:\alfred\
c:\fred\
c:\fred\tom\fred\dick.htm
c:\fred\tom\fred\harry\freda\x.htm
c:\fred\x\y\freda\x.htm
c:\xfred2\
c:\xfred2\yfreddofred\

and these would become
c:\alALFREDO\
c:\ALFREDO\
c:\ALFREDO\tom\ALFREDO\dick.htm
c:\ALFREDO\tom\ALFREDO\harry\ALFREDOa\x.htm
c:\ALFREDO\x\y\ALFREDOa\x.htm
c:\xALFREDO2
c:\xALFREDO2\yALFREDOdofred\


If the solution requires PIDL's I could use some code, because I really don't understand them.

thanks


0
Comment
Question by:Mutley2003
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 

Author Comment

by:Mutley2003
ID: 18058161

I found this


http://groups.google.com.au/group/microsoft.public.win32.programmer.ole/browse_thread/thread/b4f175cddd647516/7bb619fffb08100%237bb619fffb08100

using IshellFolder SetNameOf

but I don't quite understand what the suggested solution means "you are passing a complex pidl to SetNameOf.  SetNameOf requires a single-level pidl."

I still don't know if PIDL's are the way to go, though.
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 2000 total points
ID: 18058553
Actually, you can use the findfirst/next/close to get the path names, perform the string replace on just the relative portion (path), rename the path, then iterate down the new path.

Russell


Example:

function PathReplace(Root: String; OldPattern, NewPattern: String; Flags: TReplaceFlags; var FailedMove: String): Boolean;
var  listPaths:     TStringList;
     srFind:        TSearchRec;
     szNewPath:     String;
     szRoot:        String;
     dwFind:        Integer;
begin

  // Set default result
  result:=True;

  // Get root path
  szRoot:=ExcludeTrailingBackslash(Root);

  // Create list to hold the result
  listPaths:=TStringList.Create;

  // Resource protection
  try
     // Find first
     dwFind:=FindFirst(szRoot + '\*.*', faAnyFile, srFind);
     // Check find
     if (dwFind = 0) then
     begin
        // Resource protection
        try
           // Repeat
           repeat
              // Check for path
              if ((srFind.Attr and faDirectory) = faDirectory) and not((srFind.Name = '.') or (srFind.Name = '..')) then
              begin
                 // Add path to the list
                 listPaths.Add(srFind.Name);
              end;
           // Find next
           until not(FindNext(srFind) = 0);
        finally
           // Close the find
           FindClose(srFind);
        end;
     end;
     // Walk the list
     for dwFind:=0 to Pred(listPaths.Count) do
     begin
        // Perform string replace on existing path
        szNewPath:=StringReplace(listPaths[dwFind], OldPattern, NewPattern, Flags);
        // Check for change
        if not(CompareStr(szNewPath, listPaths[dwFind]) = 0) then
        begin
           // Move the old to new
           result:=MoveFileEx(PChar(szRoot + '\' + listPaths[dwFind]), PChar(szRoot + '\' + szNewPath), MOVEFILE_REPLACE_EXISTING);
        end;
        // Check result
        if result then
           // Iterate the new path
           result:=PathReplace(szRoot + '\' + szNewPath, OldPattern, NewPattern, Flags, FailedMove)
        else
           // Failed to move, set failed move path
           FailedMove:=szRoot + '\' + szNewPath;
        // Check result, break on failure
        if not(result) then break;
     end;
  finally
     // Free the list
     listPaths.Free;
  end;

end;

procedure TForm1.Button1Click(Sender: TObject);
var  szFail:        String;
begin

  if not(PathReplace('c:\temp', 'fred', 'ALFREDO', [rfIgnoreCase], szFail)) then
     ShowMessage(Format('Failed to move "%s"', [szFail]));

end;
0
 

Author Comment

by:Mutley2003
ID: 18058849
Thanks Russell ... lovely code, as usual.

Interestingly, MOVEFILE_REPLACE_EXISTING according to my copy of the SDK says "This value cannot be used if lpNewFileName or lpExistingFileName names a directory" but I will try it and see

For this application, where I am not trying to move files across drives, there does not seem to be any reason why I could not use MoveFile instead of MoveFileEx.

Anyway, I will do some quick tests but I am sure it will work beautifully
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 18059014

Thanks,
I tested it with the paths as defined above, and it was working ok. Didn't try any name collisions, but the code is written to pick up errors and return the path that caused the problem. As to the flag, all I have for it is this:

MOVEFILE_REPLACE_EXISTING      
If a file of the name specified by lpNewFileName already exists, the function replaces its contents with those specified by lpExistingFileName.

Like I said, didn't seem to cause any problems, though as you pointed out, might not allow a rename to a path that already exists.

Russell
0
 

Author Comment

by:Mutley2003
ID: 18062846
Hi Russell

I don't know if it is some sort of logical problem or not, or a Windows issue, or just my fuzzy thinking, but I can't get a rename going where the rename would result in addition of a subdirectory to an already existing directory. This is not imho a collision issue, but a consequence of the top down nature of the approach.

I'll post this in more detail in a new question.

regards

0

Featured Post

Enroll in August's Course of the Month

August's CompTIA IT Fundamentals course includes 19 hours of basic computer principle modules and prepares you for the certification exam. It's free for Premium Members, Team Accounts, and Qualified Experts!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…
Suggested Courses
Course of the Month15 days, 6 hours left to enroll

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question