我正在使用Java类编写SFTP模块(是的。我知道这很愚蠢。是的,我知道Net :: SFTP。这是政治上我们必须这样做的原因。)
底层Java程序基本上有几个类来从服务器获取,放置,列出和删除文件。在这些调用中,您必须为其提供目录和文件。无法移出原始目录。你自己坚持做跟踪。
我决定如果跟踪你的远程目录会很好,并创建了一个Chdir方法来跟踪你所在的目录,从FTP的根目录开始。我所做的就是将目录存储在属性中,并在其他命令中使用它。很简单,也很有效。
问题是存储的目录名称越来越长。例如,如果目录是foo/bar/barfoo
,而您$ftp->Chdir("../..")
,则新目录将是foo/bar/barfoo/../..
而不是foo
。两者在技术上都是正确的,但第一个更清晰,更容易理解。
我想要一些能够简化目录名称的代码。我考虑使用File::Spec::canonpath
,但具体说明不这样做。它指的是Cwd
,但这取决于对机器的直接访问,我通过FTP连接。
我已经提出了以下代码片段,但它确实缺乏优雅。它应该更简单,更明显它在做什么:
use strict;
use warnings;
my $directory = "../foo/./bar/./bar/../foo/barbar/foo/barfoo/../../fubar/barfoo/..";
print "Directory = $directory\n";
$directory =~ s{(^|[^.])\.\/}{$1}g;
print "Directory = $directory\n";
while ($directory =~ s{[^/]+/\.\.(/|$)}{}) {
print "Directory = $directory\n";
}
$directory =~ s{/$}{};
print "Directory = $directory\n";
有什么想法吗?我想避免安装CPAN模块。它们在我们的服务器上安装起来非常困难。
答案 0 :(得分:6)
如果我写这篇文章,我会将目录字符串拆分为/
并迭代每一段。保持一堆片段,..
条目意味着“pop”,.
意味着什么都不做,而其他任何东西都意味着将该字符串推入堆栈。完成后,只需使用/
作为分隔符加入堆栈。
my @parts = ();
foreach my $part (File::Spec->splitdir($directory)) {
if ($part eq '..') {
# Note that if there are no directory parts, this will effectively
# swallow any excess ".." components.
pop(@parts);
} elsif ($part ne '.') {
push(@parts, $part);
}
}
my $simplifiedDirectory = (@parts == 0) ? '.' : File::Spec->catdir(@parts);
如果你想保留领先的..
条目,你将不得不这样做:
my @parts = ();
my @leadingdots = ();
foreach my $part (File::Spec->splitdir($directory)) {
if ($part eq '..') {
if (@parts == 0) {
push(@leadingdots, '..');
} else {
pop(@parts);
}
} elsif ($part ne '.') {
push(@parts, $part);
}
}
my $simplifiedDirectory = File::Spec->catdir((@leadingdots, @parts));
答案 1 :(得分:2)
我在CPAN上有一个纯粹的Perl模块用于修剪路径:Path::Trim。从您的工作目录下载,复制和使用它。应该很容易。
答案 2 :(得分:1)
我不确定您是否可以访问该目录。
如果可以,您可以转到该目录并在那里getcwd
执行:
my $temp = getcwd; # save the current directory
system ("cd $directory"); # change to $directory
$directory = getcwd;
system ("cd $temp"); # switch back to the original directory
答案 3 :(得分:0)
SFTP协议支持执行您想要的实际路径命令。