如何确定两个句柄是否引用同一个文件

时间:2019-02-07 18:03:04

标签: perl handler stat filehandler

我想检查两个文件句柄是否引用同一个文件。为此,我可以使用应用于每个文件句柄的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);

2 个答案:

答案 0 :(得分:4)

通常不能(便携式地)做到这一点,可以理解,因为“文件”句柄根本不需要与文件关联。您可以做的一件事是记录每个文件句柄的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系统可以使用(设备和)索引节点编号

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

可以使用软链接(符号链接)和硬链接来更改数据,并使用不同的名称。因此,我们可以使用不同的文件名,但使用相同的“文件”(数据)。

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

此外,非规范名称以及大小写不同(在不区分大小写的系统上),某些系统上的短/长名称(更多?)...可以为同一文件指定不同的名称。使用模块可以更轻松地进行清理,但是还需要添加它。

在大多数(所有其他)系统上,inode的概念以及任何可用的类似stat的功能都使这些问题不再存在,因为device + inode唯一地引用数据。

感谢ikegami对此发表评论。

答案 1 :(得分: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

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