3

My end goal is to copy all the relevant files from one folder to another. So e.g. we have C:\Users\Tool\Desktop\test\oldStuff. In the folder oldStuff we have more folders as well as some mp3,mp4 and txt files.

Now what I would like to do is copy all the mp4 files that are smaller than a GB to C:\Users\Tool\Desktop\test\New_Stuff_Less_than_a_Gig, and the .mp4 files that are bigger than a GB to C:\Users\Tool\Desktop\test\New_STuff_Bigger_than_a_Gig.

I though is this would be pretty easy but I was wrong. So far have this, didn't worry about file type for now so just made it *.*

 procedure TForm4.Button1Click(Sender: TObject);
 var
   f: TSearchRec;
   Dir: string;
 begin
    if not SelectDirectory(Dir,widestring(Dir),Dir) then   Exit;
    FileMode:=0;
    if FindFirst(Dir+'\*.*',faAnyFile,f) = 0 then
    repeat
         try
          if (f.Attr and faDirectory ) < $00000008 then
          CopyFile(PChar(Dir+'\'+f.Name),PChar
 ('C:\Users\Tool\Desktop\test\new\'+f.Name),false);
         except
          on e: exception do
            ShowMessage(E.Message);
         end;
    until findNext(f) <> 0
 end;

which will copy anything in the folder that is selected but it doesn't copy anything from the folders within the selected folder. E.g. if we have C:\Users\Tool\Desktop\test\oldStuff\movie.mp4 it will copy the Movie.mp4 file but if we have C:\Users\Tool\Desktop\test\oldStuff\movies\Movie.mp4 it won't copy the Movie.mp4 file. I though I could just do something like this

CopyFile.size < 1000 (PChar('C:\Users\Tool\Desktop\test\oldStuff\*.*'+f.Name),
                   PChar('C:\Users\Tool\Desktop\test\new_Stuff\'+f.Name),false)

or even just

CopyFile (PChar('C:\Users\Tool\Desktop\test\old\*.*'+f.Name),
                   PChar('C:\Users\Tool\Desktop\test\new\'+f.Name),false);

but it didn't copy anything.

Elias Soares
  • 9,884
  • 4
  • 29
  • 59
Studying.com
  • 109
  • 1
  • 4
  • 10
  • 2
    SHFileOperation or IFileOperation. Stand on top of the system. – David Heffernan Mar 21 '15 at 13:37
  • 3
    FWIW, there are many many mistakes in your code. Starting with mixing GUI code and file copying in one function. Continuing with an absence of error checking, an erroneous attribute test and a badly places exception handler. – David Heffernan Mar 21 '15 at 14:53
  • Hi David , thanks will Google both shortly and see what I come up with, thanks for the heads up.@DavidHeffernan – Studying.com Mar 21 '15 at 15:17
  • 1
    I rolled back your edit. You can't change the entire question after you've received answers to it. If you now have a different question about a totally different approach, create a new question and ask it there. – Ken White Mar 21 '15 at 21:11
  • Remove the `*` in both places where you use `SameText`. They're not in my code in my answer, and they don't belong in yours either. `*.txt` is not a valid file extension, and `ExtractFileExt` returns a **file extension**. `*.txt` will **never** be the same text as `*.txt`, because *they're not the same text*. – Ken White Mar 21 '15 at 23:19
  • Or better yet, update it to use the current version of my code, which removes the need to use the extension inside that test at all. – Ken White Mar 21 '15 at 23:25

1 Answers1

6

Here's an example (done in XE7) that will do what you want. You'll need to modify it to suit your needs, obviously; it has hard-coded path information and file mask (*.png) and uses a constant to decide whether the file is large or small.

It's based on this sample directory tree:

D:\TempFiles
  |--\Test
  |-----\A
  |-----\B
  |--------\SubB   
  |-----\NewFiles
  |-------\Large
  L-------\Small

It finds all of the .png files in D:\TempFiles\Test and it's subfolders, and copies the ones equal to or larger than 10KB to D:\TempFiles\NewFiles\Large and the ones smaller than 10KB to D:\TempFiles\NewFiles\Small.

You'll need to add IOUtils and Types to your implementation uses clause.

procedure TForm1.Button1Click(Sender: TObject);
var
  aLargeFiles: TStringDynArray;
  aSmallFiles: TStringDynArray;
const
  LargeSize = 10 * 1024;
  SourcePath = 'D:\TempFiles\Test\';
begin
  aLargeFiles := TDirectory.GetFiles(SourcePath, '*.png',
                   TSearchOption.soAllDirectories,
                   function (const Path: string; const SR: TSearchRec): Boolean
                   begin
                     Result := (SR.Size >= LargeSize);
                   end);
  aSmallFiles := TDirectory.GetFiles(SourcePath, '*.png',
                   TSearchOption.soAllDirectories,
                   function(const Path: string; const SR: TSearchRec):Boolean
                   begin
                     Result := (SR.Size < LargeSize);
                   end);
  CopyFilesToPath(aLargeFiles, 'D:\TempFiles\NewFiles\Large\');
  CopyFilesToPath(aSmallFiles, 'D:\TempFiles\NewFiles\Small\');
end;

procedure TForm1.CopyFilesToPath(aFiles: array of string; DestPath: string);
var
  InFile, OutFile: string;
begin
  for InFile in aFiles do
  begin
    OutFile := TPath.Combine( DestPath, TPath.GetFileName( InFile ) );
    TFile.Copy( InFile, OutFile, True);
  end;
end;
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 1
    The OP asked to copy files from subfolders as well, but this code does not recurse onto any subfolders. – Remy Lebeau Mar 21 '15 at 17:27
  • 1
    @Remy: Rewrote to use `TDirectory.GetFiles` and recurse subdirectories. – Ken White Mar 21 '15 at 18:49
  • Hi Ken , not sure why but the {CopyFilesToPath} is bouncing back as a undeclared identifier. will play around with it a bit and try add it to what I have already. @KenWhite – Studying.com Mar 21 '15 at 19:34
  • It's right there in the code I posted - you can read it yourself. You need to add it as a form method (click on it and hit Ctrl+Shift+C, or add it to the form's declaration manually. – Ken White Mar 21 '15 at 19:40
  • Hi Thanks Ken , I added it manually. now it says the 's' in OutFile := ExtractFileName(s); is an undeclared identifier . – Studying.com Mar 21 '15 at 20:48
  • 3
    There was just a small mistake using the wrong variable. I just corrected that and changed all to use the tools from IOUtils – Sir Rufo Mar 21 '15 at 21:04
  • Hi Rufo, thanks but it doesn't copy =( ... I will do more googleing tomorrow. thanks for all the help guys learnt a lot.@SirRufo – Studying.com Mar 21 '15 at 22:43
  • @Chewy: The code **does** copy. I tested it before posting it, and it correctly copied the files in my test directories just as I explained in my answer. If it's not working for you, you did something wrong. – Ken White Mar 21 '15 at 23:07
  • @Chewy: My code copies fine, if you remove the two errors you introduced, as I've explained in my comment to your question. – Ken White Mar 21 '15 at 23:20
  • Hi Thanks, Ken works like a dream, thank you so much for the help, I don't have the rep top give you the answer. I feel a bit ashamed that I got stuck on so many easy questions and needed help with such small things. am busy looking up all the functions you called. – Studying.com Mar 22 '15 at 09:45
  • 1
    Actually, you do. You can accept answers to your own question, even with zero rep. In fact, you've [done it before](http://stackoverflow.com/questions/26811784/reading-the-last-line-in-a-tmemo-in-delphi). – Ken White Mar 22 '15 at 15:28
  • Thanks Ken, I accepted your answer and I edited my post back to the original question. sorry about changing it. @KenWhite – Studying.com Apr 04 '15 at 23:21