Как проверить, содержит ли имя файла информацию каталога?
Я хотел бы проверить, есть ли в имени файла какая-либо информация о каталоге, желательно без использования системно-зависимого хака, такого как index($file_name,'/')!=-1
, Я знаю о File::Spec
модуль, но не могу найти способ использовать этот модуль, чтобы сделать это определение. Возможно, другой модуль будет работать лучше. Вот несколько примеров имен файлов:
# This does not have directory info, so the test should fail (i.e., return false)
my $file_name1='abc.txt';
# These do have directory info, so the test should succeed (i.e., return true)
my $file_name2='dir/abc.txt';
my $file_name3='/home/me/abc.txt';
my $file_name4='~me/abc.txt';
4 ответа
splitdir
вернет список. Оценивается в скалярном контексте, возвращает количество элементов в списке. Если в списке более 1 элемента, то вы знаете, что существует разделитель каталогов.
use warnings;
use strict;
use File::Spec qw();
while (<DATA>) {
chomp;
if (File::Spec->splitdir($_) > 1) {
print 'PASS';
}
else {
print 'FAIL';
}
print ": $_\n";
}
__DATA__
abc.txt
dir/abc.txt
/home/me/abc.txt
~me/abc.txt
Печать:
FAIL: abc.txt
PASS: dir/abc.txt
PASS: /home/me/abc.txt
PASS: ~me/abc.txt
ПРИМЕР
($volume,$directories,$file) =
File::Spec->splitpath( $path );
splitpath Разбивает путь на части тома, каталога и имени файла. В системах без понятия объема возвращает "для объема".
Вы должны использовать File::Spec
чтобы получить правильно переносимый результат.
Если сложность вас беспокоит, вы должны написать свою собственную библиотеку File::Spec
функции.
Это может выглядеть так
файл PathLib.pm
package PathLib;
use strict;
use warnings;
require File::Spec;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(has_path);
sub has_path {
my ($volume, $path, $name) = File::Spec->splitpath($_[0]);
return ($path or $volume)
}
и вы могли бы использовать это так. (В настоящее время я работаю на ноутбуке с Windows и не могу проверить версию Unix, пока не доберусь до рабочего стола, но я уверен, что это сработает для вас.)
use strict;
use warnings;
use PathLib qw(has_path);
my @paths = qw{
C:\aa\bb\cc.txt
E:ee.txt
cc.txt
ee\
};
for (@paths) {
printf "%6s - %s\n", has_path($_) ? 'true' : 'false', $_;
}
выход
true - C:\aa\bb\cc.txt
true - E:ee.txt
false - cc.txt
true - ee\
В Perl /
всегда зарезервирован как разделитель каталогов (за исключением старой системы Mac OS [6-9], которая настаивала на том, чтобы она была :
). Однако в других операционных системах могут использоваться и другие символы. Например, на компьютерах с Windows оба они ссылаются на один и тот же каталог:
$file = 'C:\this\that\foo.txt';
$file = "C:/this/that/foo.txt";
Таким образом, вы всегда должны подозревать, что /
это каталог, если вы не на старом Mac. Кроме того, вы должны выяснить, каким может быть текущий разделитель путей в этой системе, и найти его тоже.
Я надеялся, что File::Spec или File::Path могут иметь какую-либо функцию или метод, который показывает имя предпочтительного разделителя каталогов, но это не документировано.
Просматривая код различных File::Spec
субмодули, я вижу, что фактический разделитель файлов жестко запрограммирован, а функции являются более сложными, чем я первоначально думал. Никаких специальных скрытых функций. Убирайся.
Тем не менее, хорошая новость заключается в том, что File::Spec
это стандартный модуль, поэтому нет причин бояться его. Он даже был включен в Perl 5.8.8. Вам не нужно беспокоиться, что он может быть не установлен.
Я сделал простой тест:
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use File::Spec;
while ( my $file = <DATA> ) {
chomp $file;
my ( $volume, $directory, $file ) = File::Spec->splitpath( $file );
if ( $directory ) {
say qq('$volume' '$directory' '$file' contains directory stuff);
}
else {
say qq('$volume' '$directory' '$file' is pure file);
}
}
__DATA__
Foo/Bar.txt
/Bar.txt
Bar.txt/
Foo_Bar.txt
Результаты были:
'' 'Foo/' 'Bar.txt' contains directory stuff
'' '/' 'Bar.txt' contains directory stuff
'' 'Bar.txt/' '' contains directory stuff
'' '' 'Foo_Bar.txt' is pure file
Кажется, что каждый раз, когда появляется разделитель каталогов, строка считается файлом. Я думаю, это имеет смысл.
Это одна из тех задач, которые в конечном итоге оказываются более сложными, чем вы себе представляете (например, определение, является ли строка действительным адресом электронной почты или номером). Лучше всего использовать File::Spec->split
и убедитесь, что там нет тома или каталога.