[2 days left] What’s wrong with your cloud strategy? Learn why multicloud solutions matter with Nimble Storage.Register Now

x
?
Solved

Renaming folders and subfolders with a pattern

Posted on 2006-12-01
5
Medium Priority
?
391 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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

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…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Video by: ITPro.TV
In this episode Don builds upon the troubleshooting techniques by demonstrating how to properly monitor a vSphere deployment to detect problems before they occur. He begins the show using tools found within the vSphere suite as ends the show demonst…
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Suggested Courses

656 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