Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Re: Perl - Copy files to a newly created folder

by dasgar (Priest)
on Apr 18, 2015 at 17:25 UTC ( [id://1123893]=note: print w/replies, xml ) Need Help??


in reply to Perl - Copy files to a newly created folder

Although you can use opendir and readdir to search through a directory, I think that using File::Find may be a better approach. I have to admit that I personally struggle to understand how to use File::Find directly, so I opt to use File::Find::Rule instead, which provides a different interface to File::Find.

Here's a different approach using File::Find::Rule:

use strict; use warnings; use feature 'say'; use File::Copy; use File::Spec::Functions; use File::Find::Rule; use File::Path qw(make_path); use Cwd; my $pwd = cwd(); my $dir = catdir($pwd,'source'); my $rule = File::Find::Rule->new; $rule->file; $rule->maxdepth(1); my @files = $rule->in($dir); foreach my $file (@files) { my ($extension) = ($file =~ m/.+\.(.+)/); my $subdir = catdir($dir,$extension); if (!(-d $subdir)) {make_path($subdir);} copy($file,$subdir); }

Here's the initial test directory that I used to test the script:

source test1.gif test1.pdf test1.txt test2.gif test2.pdf test2.txt test3.gif test3.pdf test3.txt

Here's the result after running the script:

source test1.gif test1.pdf test1.txt test2.gif test2.pdf test2.txt test3.gif test3.pdf test3.txt gif test1.gif test2.gif test3.gif pdf test1.pdf test2.pdf test3.pdf txt test1.txt test2.txt test3.txt

Although my code above doesn't deal with deleting the original file, I think that you should be able to modify it to meet your needs.

Replies are listed 'Best First'.
Re^2: Perl - Copy files to a newly created folder
by Benichouniev (Novice) on Apr 18, 2015 at 18:51 UTC

    Dasgar,
    thanks for your answer. Unfortunately, I don't want to have to download anything additional to run my program (for the find rule).
    Instead, would you have an idea of how to improve my program with what I have right here and my current set of skills? As I said, I am no Perl expert and this code, right above, is what I can do.
    I really appreciate your help but I need something less complicated. I know it is possible, because I managed to copy a few files with this code already, now I just want to be able to copy everything and understand why it does not work.
    Also, I apologize if my English if a bit off, but since I am French, you will have to excuse my awkward syntaxes sometimes ;). Thanks!
    Ben

      I don't want to have to download anything additional to run my program (for the find rule).

      I'm not sure that I understand your reluctance to install additional modules. One of the strengths of Perl is leveraging the modules available at CPAN. To install File::Find::Rule, you just need to type cpan -i File::Find::Rule. But if you're insisting on not installing additional modules, I won't pressure you to do what you don't want to do.

      Instead, would you have an idea of how to improve my program with what I have right here and my current set of skills?

      Unfortunately you really haven't provided enough details. I don't know what kind of files that you have that you're trying to copy/move and you're not really providing enough details about what copied and what didn't. Without more information, I'd have to agree with aaron_baugher's suggestions (Re: Perl - Copy files to a newly created folder) as a good starting point for debugging your script.

      I really appreciate your help but I need something less complicated.

      Other than possibly learning a new module, I really don't think that the code in my last post was really complicated. In fact, I personally think that trying to use opendir/readdir/closedir is actually a bit more complicated than using File::Find::Rule since you now have to do more work.

      Here's a modification of my previous code using only core modules and using opendir/readdir/closedir in place of File::Find::Rule.

      use strict; use warnings; use feature 'say'; use File::Copy; use File::Spec::Functions; use File::Path qw(make_path); use Cwd; # getting the "source" directory my $pwd = cwd(); my $source_dir = catdir($pwd,'source'); my @files; opendir(my $dir,$source_dir) or die "Unable to open directory '$source +_dir': $!"; # search for files in the specified directory while (my $item = readdir($dir)) { # skip . and .. next if ($item =~ m/^\./); # skip directories next if (-d $item); # if this is a file, add it to the @files array my $test = catfile($source_dir,$item); if (-f $test) {push @files,($item);} } closedir($dir); # process the files found foreach my $file (@files) { # get the file's extension my ($extension) = ($file =~ m/.+\.(.+)/); my $subdir = catdir($source_dir,$extension); # if the folder for the extension does not exist, create it if (!(-d $subdir)) {make_path($subdir);} my $source = catfile($source_dir,$file); my $target = catfile($subdir,$file); # copy the file to the appropriate folder copy($source,$subdir); # move the file to the appropriate folder #move($source,$target); }

      In this version, I'm using a while loop to process through the contents of the directory. In that loop, I'm needing to be aware of and handle the special cases of . and .. plus and I need to ignore directories. Actually, I might have gotten away without checking for those items and using just the -f check. However, I put those additional checks in there, because I have gotten in trouble in the past for not checking them. So I now have a habit of including those checks whenever I use readdir to look at a directory's contents.

      (I did notice that fishmonger showed a different method for finding files in a directory by using grep, but I thought I'd stick with using readdir since that's what you originally were trying to use.)

      Also, notice that in the foreach loop that the @files array has only relative file names and not full path file names (i.e. has file.txt and not C:\directory\file.txt). Although I chose to "fix" this in the foreach loop, I could have done the "fix" back in the while loop before adding each file name to the @files array.

      Let me share something else. I used to use the readdir method to go find items in a directory. But it can get real cumbersome - especially if you wish to search through subdirectories too. I kept seeing a lot of folks recommending File::Find as a better way to handle that kind of task. As I mentioned in my last post, I never could get my head wrapped around how to use File::Find. At some point I discovered File::Find::Rule and I found it to be super easy to understand how to use. Now when I need to go find and process directory contents, I just use File::Find::Rule. Doing so, I can accomplish the search with 10 or less lines instead of using one or more loops that feel complicated and hoping that I have code that handles everything properly. Although you may be more comfortable with using readdir for this current work, I'd recommend that you look into learning File::Find and/or File::Find::Rule at some point.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1123893]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-04-24 01:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found