Perl 中的目录句柄无法正常工作

Posted

技术标签:

【中文标题】Perl 中的目录句柄无法正常工作【英文标题】:Directory Handle in Perl Not Working Properly 【发布时间】:2020-08-15 18:07:28 【问题描述】:

我正在尝试使用目录句柄读取 Perl 文件夹中的文件。该脚本能够显示文件名,但会引发两个错误:readdir() attempted on invalid dirhandle DIRclosedir() attempted on invalid dirhandle DIR

我正在调用一个子程序并传递两个值:

if($fileEnding eq "directory")

  print "$fileName is a directory\n";
  FolderInvestigator1($a, $fileName);

$a 保存通过命令行参数传递的目录名称及其路径。我将控制权传递给子程序。

下面是我的代码:-

sub FolderInvestigator1

  my $prevPath = shift;
  my $receivedFolder = shift;
  my $realPath = "$prevPath/$receivedFolder";
  my $path = File::Spec->rel2abs($realPath);
  print "$path\n";
  print "$receivedFolder Folder Received\n";
  opendir(DIR, $path) or die "You've Passed Invalid Directory as Arguments\n";  
  while(my $fileName = readdir DIR)
  
    next if $fileName =~ /^\./;
    print "The Vacant Folder has $fileName file\n";
  
  closedir(DIR);

这是我的完整代码:-

FirstResponder();

sub FirstResponder

  if (@ARGV == 0)
  
    print "No Arguments Passed\n";
  


else

    foreach my $a(@ARGV)
    
        print "Investigating $a directory below:-\n";

        opendir(DIR, $a) or die "You've Passed Invalid Directory as Arguments\n";                       
        while(my $fileName = readdir DIR)
        
            next if $fileName =~ /^\./;
            $ending = `file --mime-type $a/$fileName`;
            #print $ending;

            $fileEnding = `basename -s $ending`;                
            #print $fileEnding;
            chomp($fileEnding);
            #print $fileName,"\n";
            if($fileEnding eq "directory")
            
                print "$fileName is a directory\n";
                FolderInvestigator1($a, $fileName);
            

            else
            
                CureExtensions($a, $fileName);
                   
        
        closedir(DIR);  
        my @files = glob("$a/*");
        my $size = @files;
        if($size == 0)
        
            print "The $a is an empty directory\n";
           
    
#Foreach Ends Here..

请查看屏幕截图以了解更多信息!

即使我使路径正确,我也无法理解为什么目录句柄会引发错误。一些指导将不胜感激。

【问题讨论】:

您正在第二次使用opendir(DIR, ...) ... closedir(DIR),然后才完成第一个句柄DIR。我建议你使用词法目录句柄而不是全局句柄。 嗨@HåkonHægland。谢谢你的建议。我实际上是 Perl 的新手,因此任何有关 Lexical Dir Handles 的参考资料对我来说都是很棒的。谢谢!! @Leon S Kennedy Lexial 文件和目录句柄只是您使用的标量变量,而不是DIR - 该变量获取对句柄的引用。使用类似my $dirhandle; opendir($dfirhandle, $a) or die;(或opendir(my $dirhandle, $a)...,如果你想花哨的话。my 使它成为词法(范围私有)。 嗨@Silvar,感谢您的通知。我尝试使用它们。但是,错误仍然存​​在。实际上,我在最上面声明了它。顺便说一句,没有进展。 你的脚本中有use strict; use warnings;吗? 【参考方案1】:

您的代码的问题在于您嵌套使用了裸字(全局)目录句柄 DIR,因此内循环在外循环完成之前关闭句柄:

opendir(DIR, $arg) or die "...";
while(my $fileName = readdir DIR) 
    # ... more code here
    opendir(DIR, $path) or die "...";
    while(my $file = readdir DIR)  
        # ... more code here
    
    closedir DIR;

closedir DIR;

这是一个示例,说明如何使用词法目录句柄 $DIR 而不是使用旧的全局裸字句柄 DIR 编写第一个循环:

use feature qw(say);
use strict;
use warnings;
use File::Spec;

FirstResponder();

sub FirstResponder 
    foreach my $arg (@ARGV) 
        print "Investigating $arg directory below:-\n";
        opendir(my $DIR, $arg) or die "You've Passed Invalid Directory as Arguments\n";
        my $size = 0;
        while(my $fileName = readdir $DIR) 
            next if $fileName =~ /^\./;
            my $path = File::Spec->catfile( $arg, $fileName );
            if( -d $path) 
                print "$fileName is a directory\n";
                say "FolderInvestigator1($arg, $fileName)"
            
            else 
                say "CureExtensions($arg, $fileName)";
            
            $size++;
        
        closedir $DIR;  
        if($size == 0) 
            print "The $arg is an empty directory\n";
        
    

根据perldoc open:

一种较旧的风格是使用裸词作为文件句柄,如

open(FH, "<", "input.txt")
   or die "Can't open < input.txt: $!";   

然后你可以使用 FH 作为文件句柄,关闭 FH 等等。请注意,它是一个全球性的 变量,所以不建议在新代码中使用这种形式。

另见:

Why does Perl open() documentation use two different FILEHANDLE style? Don't Open Files in the old way

【讨论】:

嗨@Håkon Hægland,我实施了您的解决方案。错误消失了。你能告诉我catfilesay吗?我在终端里得到了这样的东西:-FolderInvestigator1(ImageFolder, Vacant)CureExtensions(ImageFolder, Paper.png)CureExtensions(ImageFolder, Stone.gif)。谢谢一百万! 我使用了catfile,因为readdir 没有在文件名前添加目录名。然后catfile($dir, $filename) 将这两个部分连接起来。

以上是关于Perl 中的目录句柄无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中获取当前工作目录路径

Perl文件目录常用操作

如何将 Perl 的 system() 的输出重定向到文件句柄?

使用供应商目录中的 autoloader.php 自动加载无法正常工作

Perl 无法在 Windows 10 中找到现有目录

在 Perl 脚本中无法将目录添加到存档