Solved

Renaming folders and subfolders with a pattern

Posted on 2006-12-01
5
381 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 500 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 June's Course of the Month

June's Course of the Month is now available! Every 10 seconds, a consumer gets hit with ransomware. Refresh your knowledge of ransomware best practices by enrolling in this month's complimentary course 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

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Come and listen to Percona CEO Peter Zaitsev discuss what’s new in Percona open source software, including Percona Server for MySQL (https://www.percona.com/software/mysql-database/percona-server) and MongoDB (https://www.percona.com/software/mongo-…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…

695 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