What can I say?
($size) = ( ( qx{ dir /s $TargetPath | find "bytes" } )[-2] =~ /([\d, +]+) bytes/ ); print "$TargetPath : $size" \\HIAWATHA\C$\test : 22,578,657
The only explanation I can think of for the error you posted is that the find command is not available, or not in the path for the userid under which your code is running. The command is provided by the file find.exe which is a standard part of every Windows version I am aware of. It is usually located in
%systemroot%\system32\find.exe
which in turn is usually in the standard path setting. I can't imagine why this would not be the case on your system but you could try modifying the line to explicitly run it from the appropriate place.
my ($Size)=( (qx{dir /s "$TargetPath" | %SystemRoot%\\system32\\find " +bytes" })[-2]=~ /([\d,]+ 002 +) bytes/ );
Note: You'll need to check that the environment variable %SystemRoot% is available and that find.exe is actually available and visible to you.
Did you consider trying the command from a CLI?
use Win32::OLE; $fso = Win32::OLE->CreateObject('Scripting.FileSystemObject'); $f = $fso->GetFolder( '\\HIAWATHA\c$\test' ) or warn $^E; print $f->Size; 22578657
You'll notice that this is the same value (minus the commas) as produced by the dir /s method above.
(@dirs, @files) = ( '//HIAWATHA/c$/test' ); scalar map{ push @{ (-d) ? \@dirs : \@files }, $_ } glob pop(@dirs) . +'/*' while @dirs; $size += -s for @files; print $size; 22578657
Again, the number produced is identical to the other two.
The only problem I can find with this is that glob doesn't seem to accept UNC paths that use backslashes. It accepts standard paths with backslashes.
This worksperl -le " print for glob 'c:\test\*'"
As do full UNC paths using forward slashes
perl -le " print for glob '//HIAWATHA/c$/test/*' "
But not UNC paths with backslashes :(. All of the following silently fail!
P:\test>perl -Mstrict -wle " print for glob '\\\\HIAWATHA\\c$\\test\\* +' " P:\test>perl -Mstrict -wle " print for glob '\\\\HIAWATHA\\c$\\test\\* +' " P:\test>perl -Mstrict -wle " print for glob '\\\\HIAWATHA\\c\$\\test\\ +*' " P:\test>perl -Mstrict -wle " print for glob qq[\\\\HIAWATHA\\c\$\\test +\\*] "
Which as your code is set up to send full UNC paths to CMD which requires the backslashes probably explains that failure. I hadn't noticed this as I invariably use forward slashes accept when passing things to CMD.
Just for completeness, I also tested the File::Find route that Aristotle posted. With the caveat that this also requires the use of forward slashes rather than backslashes for UNC paths, it also works and produces identical results to the other three.
use File::Find; $size = 0 find(sub { $size += -s _ if -f }, '\\HIAWATHA\c$\test' ); Can't stat \HIAWATHA\c$\test: No such file or directory at (eval 4) line 1 find(sub { $size += -s _ if -f }, '\\\\HIAWATHA\\c\$\\test' ); Can't stat \\HIAWATHA\c\$\test: No such file or directory at (eval 5) line 1 find(sub { $size += -s _ if -f }, '//HIAWATHA/c$/test/' ); print $size; 22578657
So, all four methods will work, though they may not be "drop in" replacements for you original line of code, the effort required to make them so is minimal.
Of course, this wouldn't be complete without answering the question that we are all dying to know the answer to:). Which is the fastest?
Sorry, but despite my best efforts, I have been unable to arrive a consistant set of figures. The effects of multiple levels of caching, (disk caching, network redirector caching, perl caching stuff) mean that I can get different "winners" each time I re-run the tests. For reasons that I can't begin to explain, I can even get different results on the first run after a re-boot.
Suffice it to say, once a network is involved (as opposed to my simulations within the same box), method 1 is likely to loose out badly simply because of the volumes of data being generated and discarded. This is true regardless of whether the discarding is done externally using the find filter, or internally to perl. Though saving perl from having to allocate large amounts of memory to store the huge lists generated is substantial of itself.
I also encountered a occasional anomolies where the OLE code would bottle out with access denied errors, but they where not consistant, and immediatley after failure, running identical code but from a VBScript, produced no such errors, so it looks like there may be a problem somewhere in the Win32::OLE code. If I manage to tie down a reproducable testcase, I'll report this.
I conclude that either of the perl solutions seems to be a good choice, as they both suffer the same limitations regarding the UNC path syntax and from what I can tell the difference in speed in minimal. The File::Find route is undoubtably cleaner code, so I would recommend Aristotles version over any of the three I offered.
HTH.
In reply to Re: Re: Re: Re: Re: Out of memory.
by BrowserUk
in thread Out of memory.
by blackadder
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |