Как определить, относятся ли две ручки к одному и тому же файлу - PullRequest
0 голосов
/ 07 февраля 2019

Я хотел бы проверить, ссылаются ли два дескриптора файла на один и тот же файл.Для этого можно ли использовать функцию 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 голосов
/ 08 февраля 2019

Да, в некоторых комбинациях система + устройство можно использовать 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

Все, кроме двух последних, могут быть обработаны с помощью нормализации.

0 голосов
/ 07 февраля 2019

Это не может быть сделано вообще (переносимо), , что понятно, поскольку дескриптор «файла» вообще не должен быть связан с файлом.Вы можете записать 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) ине globs (FH), используйте три аргумента open, и всегда проверяйте open call .


В некоторых(большинство?) систем Linux, которые вы можете использовать /proc файловая система

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

, и на более (всех?) системах Unix-y можно использовать номер (устройства и) индекса

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

Ссылки, как мягкие (символические), так и жесткие, могут использоваться для изменения данных и иметь разные названия.Таким образом, мы можем иметь разные имена файлов, но один и тот же файл (данные).

В системах Windows лучший способ проверки представлен в этом посте , за исключением случая с жесткой связью, для которого нужно было бы использовать метод другого ответа (вывод разбора), посколькуЯ могу сказать.

Кроме того, неканонические имена, а также различные заглавные буквы (в системах без учета регистра), короткие / длинные имена в некоторых системах (больше?) ... могут использоваться для разных имен длятот же файл.Это легче очистить, используя модули, но также необходимо добавить.

В большинстве (всех?) Других систем понятие inode и любая доступная stat -подобная функциональность делает ихпроблема, так как устройство + inode относится исключительно к данным.

Благодаря ikegami за комментарии к этому.

...