【问题标题】:How to determine if two handles refer to the same file如何确定两个句柄是否引用同一个文件
【发布时间】:2019-02-07 18:03:03
【问题描述】:

我想检查两个文件句柄是否引用同一个文件。为此,我可以使用应用于每个文件句柄的stat 函数吗? 提前致谢

my $file = 'C:\temp\file.txt');
open( TXT1, "> $file" );
open( TXT2, "> $file" );
print( "The handles refer to the same file!") if (\TXT1 eq \TXT2);

【问题讨论】:

  • 如果你在一个支持它的文件系统上,你可以比较来自stat的dev和ino值。但是,您的文件名表明您在 Windows 上,这些值没有意义。
  • 一般不能这样做。现有的文件句柄根本不需要与文件关联;可能是套接字/管道/等。您可以更改在该程序中打开文件的方式吗?然后你可以添加一个哈希来跟踪它们,例如使用fileno
  • 注意:不是文件句柄R(末尾有“r”),是文件句柄(没有“r”)。它是一个句柄——与文件相关联并提供给我们的东西,以便我们可以处理文件。
  • 第二次@zdim 的建议是使用词法文件句柄、三参数打开和错误处理。 File::Open 模块可以很好地为您包装所有这些,以及像 Path::Tiny 这样的模块。
  • @zdim,它被称为句柄,因为它允许我们持有系统资源。

标签: perl handler stat filehandler


【解决方案1】:

一般情况下(便携式)无法做到这一点,†考虑到“文件”句柄根本不需要与文件相关联,这是可以理解的。您可以做的一件事是为每个文件句柄记录fileno。

所以当打开文件时

my %filename_fileno;

open my $fh, '>', $file or die "Can't open $file: $!";

$filename_fileno{fileno $fh} = $file;

然后您可以在需要时查找它‡

say "Filename is: ", $filename_fileno{fileno $fh};

当该文件(即将)关闭时,不要忘记从哈希中删除条目

delete $filename_fileno{fileno $fh};
close $fh;

所以这些应该在实用程序函数中。正如脚注 ‡ 中概述的那样,需要更多的关注,这将是一个不错的小模块。然后也可以考虑扩展(继承)一个相关的模块,比如Path::Tiny。

注意:您不能像问题中那样从单独的文件句柄写入文件。每个文件句柄上的操作都会跟踪 那个文件句柄在文件中的最后一个位置,因此写入将破坏另一个文件句柄的中间写入。

注意:使用词法文件句柄 (my $fh) 而不是 glob (FH),使用三参数 open,并始终检查 open 调用。


†   在某些(大多数?)Linux 系统上,您可以使用/proc 文件系统

say readlink("/proc/$$/fd/" . fileno $fh);

以及更多(全部?)Unix-y 系统可以使用(设备和)inode 编号

say for (stat $fh)[0,1];

‡   软(符号)和硬链接可用于更改数据并具有不同的名称。所以我们可以有不同的文件名但相同的“文件”(数据)。

据我所知,在 Windows 系统上,this post 给出了最好的检查方法,除了硬链接情况,必须使用另一个答案的方法(解析输出)。

此外,非规范名称,以及不同的大写(在不区分大小写的系统上),某些系统上的短/长名称,(更多?)......可以为同一个文件提供不同的名称。这更容易清理,使用模块,但也需要添加。

在大多数(所有?)其他系统上,inode 的概念和任何可用的类似stat 的功能都使这些成为问题,因为设备+inode 唯一地引用数据。

感谢 ikegami 对此的 cmets。

【讨论】:

    【解决方案2】:

    是的,在某些系统+设备组合上,可以使用stat。

    use File::stat;
    
    my $st1 = stat($fh1)
       or die $!;
    my $st2 = stat($fh2)
       or die $!;
    
    say $st1->dev == $st2->dev && $st1->ino == $st2->ino ? "same" : "different";
    

    值得注意的是,这不适用于 NTFS 或 FAT32,您似乎正在使用其中之一。

    您应该让您的程序自行跟踪,但这说起来容易做起来难。当您必须处理硬链接、软链接、带有./.. 的路径、大小写/斜杠差异、短/长名称、常规/UNC 路径、股份等。

    例如,以下所有路径都可以引用同一个文件:

    • C:\Moo\Foo Bar.txt
    • C:\Hardlink\Foo Bar.txt
    • C:\Softlink\Foo Bar.txt
    • C:\.\Moo\Foo Bar.txt
    • C:\Baz\..\Moo\Foo Bar.txt
    • c:\moo\foo bar.txt
    • C:/Moo/Foo Bar.txt
    • C:\Moo\FOOBAR~1.TXT
    • \\?\C:\Moo\Foo Bar.txt
    • \\127.0.0.1\C$\Moo\Foo Bar.txt
    • Z:\Moo\Foo Bar.txt

    除了最后两个之外的所有内容都可以通过规范化处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多