Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

I go crazy with windows filenames with spaces!

by Anonymous Monk
on Jan 19, 2010 at 14:43 UTC ( #818196=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Can someone explain why this works:
opendir MYDIR, ("c:/documents\ and\ settings/username/desktop/perf +_analyzer"); print "Path:\n$path\n"; while ( $file = readdir(MYDIR)) { + print "File: ", $file, "\n"; }
and this doesn't ! (it onlyo works if there are no spaces in the filename):
$path = `cd`; # I am in c:/documents\ and\ settings/username/desktop/p +erf_analyzer $path=~s/\\/\//g; chop $path; #Why there is a space at the end??? I have to chop it +or else I will have extra backslash after second substitution... $path=~s/\s{1}/\\ /g; opendir MYDIR, $path; # Yes I have the path exactly like in previo +us code but it doesn't browse the directory. I even tried to add the +same qoutes ('"'.$path.'"') but it didn't work either. print "Path:\n$path\n"; while ( $file = readdir(MYDIR)) { + print "File: ", $file, "\n"; }

Comment on I go crazy with windows filenames with spaces!
Select or Download Code
Re: I go crazy with windows filenames with spaces!
by Corion (Pope) on Jan 19, 2010 at 14:47 UTC

    Most likely this is because when you shell out to `cd`, you get whitespace at the end of your directory. If you run with warnings enabled, Perl will tell you when you try to open a file with a newline at the end of its name. But maybe you did want to use Cwd instead anyway? Or File::Find?

      I would like to avoid any extra modules in my code. This is ok I have extra space because I know how to get rid of it. My main problem is I don't know how to make the opendir MYDIR, $pathwithspaces work...

        Well duh - if you want to avoid the stuff that comes with Perl, that's your problem then. Perl would tell you if you let Perl tell you, but you seem to be bent on doing things the hard way.

Re: I go crazy with windows filenames with spaces!
by Anonymous Monk on Jan 19, 2010 at 14:49 UTC
    You're asking why the shell command CD outputs what it does? Crazy indeed :)
    $ cd |od -tacx1 0000000 D : \ p o r t a b l e a p p s c +r D : \ p o r t a b l e a p p s \ +r 44 3a 5c 70 6f 72 74 61 62 6c 65 61 70 70 73 0d 0000020 nl \n 0a 0000021
    use Cwd;
    use Cwd; print cwd(),"\n";
Re: I go crazy with windows filenames with spaces!
by ahmad (Hermit) on Jan 19, 2010 at 15:03 UTC

    If you are running on windows XP or higher you don't need to escape the blank space.

    Try this:

    my $path = 'C:\Documents and Settings\Administrator\Desktop'; opendir(DIR,$path) or die $!; while (my $File = readdir DIR) { print "$File\n"; } closedir(DIR);

    As I remember older versions of windows only support 8 characters long file/folder name so you'll have to use 6 characters and add ~1 at the end of the file name.

    I am not very sure I haven't used old windows OS from like 6 years now

      Win32::GetShortPathName($fullpath);

        I could not find

        Win32::GetShortPathName($fullpath);

        But I've knocked up this which seems to work

        use Win32::API; sub GetShortPathName { my $GetShortPathName = new Win32::API('kernel32', 'GetShortPathName +A', 'PPN', 'N'); die "Can't import API GetShortPathNameA:\n$!" unless defined $GetSh +ortPathName; my $longpath = shift; my $length = 1 + length $longpath; my $shortpath = ' ' x ($length); $length = $GetShortPathName->Call($longpath, $shortpath, $length); return substr($shortpath, 0, $length); }
      All right! My first code works if I chop what I get from cd, so:
      $path = `cd`; chop $path; opendir MYDIR, $path; print "Path:\n$path\n"; while ( $file = readdir(MYDIR)) { + print "File: ", $file, "\n"; }
      One can really go mad when dealing with filenames in Windows. Greetings Bill... Thanks!

        Your problem is less with Windows but with your roundabout way of using Perl as if it were a command shell instead of using the Perl built-in ways.

        None of the problems you experienced are in any way related to Windows. The program would behave identically on any other OS*.

        {Bashing someone else for your own errors}--

        The space you are getting is not a space at all. It's the linefeed at the end of the line cd outputted. chomp is a better way of removing it.

        * — Actually, it'll work even less because `cd` won't work on other OSes. It only works on Windows because of a bug in the Windows part of Perl. If `cd` did work elsewhere, the rest of the program would behave identically.

      If you are running on windows XP or higher you don't need to escape the blank space.

      OS doesn't matter. opendir always takes a path for argument. Not a path that's been escaped into something else.

      As I remember older versions of windows only support 8 characters long file/folder name so you'll have to use 6 characters and add ~1 at the end of the file name.

      You're saying there exists a version of Windows that both supported long file names and didn't support long file names.

      DOS was what didn't support long file names. DOS applications running on Windows had to use the short path names. Adding ~1 is not the correct way of getting the short file name. And finally, the problem at hand has nothing to do with long file names. Or file names at all, really.

Re: I go crazy with windows filenames with spaces!
by ikegami (Pope) on Jan 19, 2010 at 15:15 UTC

    In both snippets, right before opendir, print $path. You'll notice they're different.

    "c:/documents\ and\ settings/username/desktop/perf_analyzer"
    is the same thing as
    "c:/documents and settings/username/desktop/perf_analyzer"
    Both of the above produce the string
    c:/documents and settings/username/desktop/perf_analyzer

    Expressions that produce the string

    c:\documents and settings\username\desktop\perf_analyzer
    would also be fine. Your bug is
    $path=~s/\s{1}/\\ /g;
    You are causing the string to become
    c:/documents\ and\ settings/username/desktop/perf_analyzer

    That's bad, because there's no directory c:\documents

    Fixed code:

    chomp( my $path = `cd` ); opendir MYDIR, $path or die("Can't open dir $path: $!\n");

    Even better:

    opendir MYDIR, '.' or die("Can't open current dir: $!\n");
Re: I go crazy with windows filenames with spaces!
by Marshall (Prior) on Jan 19, 2010 at 23:20 UTC
    I don't understand what your second code is supposed to do.

    The most portable way to get the "files" in a directory is to just open that directory and use grep{} to filter the names that you want. See below. Note that readdir does not give full paths, you have to prepend the directory to the $_ variable.

    Use '/', forward slash instead of '\' for file names. Windows Perl will do the "right thing". There is no need for '\\' and "backslash" unless some pathname has to go to the Windows shell.

    Updated: to show map{} function better.

    #!/usr/bin/perl -w use strict; my $user = 'SOME_USER'; my $directory = "c:/documents and settings/$user/"; opendir (MYDIR, $directory) || die "unable to open $directory"; my @file_paths = map {"$directory/$_"} grep{ -f "$directory/$_" } readdir MYDIR; # The below means the same thing. But I think that the # above grep/map filter combo is easier to understand. #my @file_paths = map { -f "$directory/$_" # ? "$directory/$_" # : () # } readdir MYDIR; # # return"()" from a map{} to return "nothing" # to get all the files (directories are files).... # my @file_paths = map{ "$directory/$_"} readdir MYDIR; foreach my $file (@file_paths) { print "$file\n"; }
      Just a note wrt Windows paths: perl does the right thing because Windows does the right thing with forward-slashes as directory separators. It's just that almost none of Windows userland does.

      The only example I can think of for a tool doing the right thing off hand is chdir in cmd.exe: cd /d c:/windows.

        I said that: Windows Perl will do the "right thing". That's a bit different than "Windows does the right thing". Perl has an amazing capacity to "un-screw" Windows quirks.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://818196]
Approved by sweetblood
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2014-07-12 17:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (240 votes), past polls