如何在Perl中获取文件的最后修改时间?

72
假设我有一个文件句柄$fh,我可以使用-e $fh检查它是否存在,或者使用-s $fh检查它的文件大小,或者使用一堆其他关于文件的信息。如何获取它的最后修改时间戳?
10个回答

111

调用内置函数stat($fh)返回一个数组,其中包含关于传递的文件句柄的以下信息(来自statperlfunc man页面):

  0 dev      device number of filesystem
  1 ino      inode number
  2 mode     file mode  (type and permissions)
  3 nlink    number of (hard) links to the file
  4 uid      numeric user ID of file's owner
  5 gid      numeric group ID of file's owner
  6 rdev     the device identifier (special files only)
  7 size     total size of file, in bytes
  8 atime    last access time since the epoch
  9 mtime    last modify time since the epoch
 10 ctime    inode change time (NOT creation time!) since the epoch
 11 blksize  preferred block size for file system I/O
 12 blocks   actual number of blocks allocated

这个数组的第9个元素将给出自时代以来( 1970年1月1日00:00 GMT )的上次修改时间。 通过这个时间你可以确定本地时间:

my $epoch_timestamp = (stat($fh))[9];
my $timestamp       = localtime($epoch_timestamp);

或者,您可以使用内置模块File::stat(从Perl 5.004开始包含)来获得更加面向对象的接口。

为了避免前面示例中需要的魔法数字9,还可以使用另一个内置模块Time::localtime(也是从Perl 5.004开始包含的)。这两者共同导致一些(可以说是)更易读的代码:

use File::stat;
use Time::localtime;
my $timestamp = ctime(stat($fh)->mtime);

localtime 是否应该纠正时区更改?例如:在PST中创建文件,然后从CET读取mtime。我得到了令人困惑的结果。 - Jonathan Cross
1
提到使用 File::stat 是误导性的,因为这将提供一种面向对象的访问 stat 信息的方式,直接访问数组元素是行不通的。没有必要使用 File::stat 来访问例如 (stat($fh))[9] - Santrix

26

使用内置的stat函数。更具体地说:

my $modtime = (stat($fh))[9]

19
my @array = stat($filehandle);
$array[9] 中存储的修改时间是以 Unix 格式存储的。
或者明确一点:
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
    $atime, $mtime, $ctime, $blksize, $blocks) = stat($filepath);

  0 dev      Device number of filesystem
  1 ino      inode number
  2 mode     File mode  (type and permissions)
  3 nlink    Number of (hard) links to the file
  4 uid      Numeric user ID of file's owner
  5 gid      Numeric group ID of file's owner
  6 rdev     The device identifier (special files only)
  7 size     Total size of file, in bytes
  8 atime    Last access time in seconds since the epoch
  9 mtime    Last modify time in seconds since the epoch
 10 ctime    inode change time in seconds since the epoch
 11 blksize  Preferred block size for file system I/O
 12 blocks   Actual number of blocks allocated

时代纪元为 1970 年 1 月 1 日 GMT 的 00:00。

更多信息可以在 stat 中找到。


16
你需要使用stat调用,并提供文件名:
my $last_mod_time = (stat ($file))[9];

Perl也有不同的版本:

my $last_mod_time = -M $file;

但该值是相对于程序启动时间的。这对于排序等操作很有用,但您可能想要使用第一个版本。


10

如果你只是比较两个文件哪个更新,则可以使用 -C

if (-C "file1.txt" > -C "file2.txt") {
{
    /* Update */
}

还有一个-M,但我不认为这是你想要的。幸运的是,通过谷歌几乎不可能搜索到关于这些文件操作符的文档。

2
еңЁи°·жӯҢжҗңзҙўдёӯеҠ е…Ҙ-MпјҢиҜ·ж·»еҠ еј•еҸ·вҖң-MвҖқпјҢеӣ дёә-XдјҡеҲ йҷӨеҢ…еҗ«Xзҡ„з»“жһң...йЎәдҫҝиҜҙдёҖдёӢпјҢ' -M 'жҳҜеҺҹеё–дҪңиҖ…жғіиҰҒзҡ„гҖӮ - Déjà vu
1
更自然的做法是使用“<”(测试“file1.txt”是否为更新的文件 - 因为“-C”返回文件的年龄,而不是(创建)日期)。 - Peter Mortensen
1
-M(内容修改)和-C(inode更改)之间的区别解释:https://unix.stackexchange.com/questions/132660/whats-the-difference-between-modification-date-and-inodes-modification-date - David L.

3
你可以使用stat()函数或File::Stat模块来实现。
perldoc -f stat

3

我认为你正在寻找stat函数(perldoc -f stat)。

特别地,返回列表中索引为9的项目(即第10个字段)是文件的最后修改时间,以自纪元以来的秒数表示。

所以:

my $last_modified = (stat($fh))[9];


2
在我的FreeBSD系统上,stat 只返回一个 bless。
$VAR1 = bless( [
                 102,
                 8,
                 33188,
                 1,
                 0,
                 0,
                 661,
                 276,
                 1372816636,
                 1372755222,
                 1372755233,
                 32768,
                 8
               ], 'File::stat' );

你需要像这样提取mtime
my @ABC = (stat($my_file));

print "-----------$ABC['File::stat'][9] ------------------------\n";

或者

print "-----------$ABC[0][9] ------------------------\n";

1

另一种选择是:$^T-(-M $fh)*3600*24

考虑到OP问了-X内置函数,我想这可能是他在寻找的东西。在某些情况下,我更喜欢它比stat()自己,虽然我不确定我是否可以为此样式上的决定辩护...

这利用了Perl将脚本开始时间保留在$^T中(有关详细信息,请参见perldoc perlvar),并且-M返回与该文件的修改时间之间的差异,作为一天的浮点分数。 它很神秘但非常perlish,并且在您没有文件句柄的情况下很适合(-X可以操作文件路径或文件句柄)。

附言:我曾经很难找到关于-X内置函数的详细信息,直到意识到在大多数perl-enabled命令行环境中可以通过perldoc -f -X找到详细信息。


1
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者和不熟悉语法的成员来说,这尤其重要。鉴于此,您能否编辑您的答案,包括您正在做什么的解释以及为什么您认为这是最好的方法? - Tyler2P
谢谢提醒!我在发布时考虑过详细阐述,但认为这是一个老问题,没有人会关心=) - GargFunk
永远不知道它会在未来帮助谁。大多数堆栈溢出的流量来自遇到相同问题的人。确保答案提供足够的细节,以便任何人,无论是否熟悉该语言,都能理解解决方案,这一点始终很重要。 - Tyler2P

1
这是一个非常古老的帖子,但我尝试使用解决方案并无法从File :: stat中获取信息。(Perl 5.10.1)
我不得不执行以下操作:
my $f_stats = stat($fh);
my $timestamp_mod = localtime($f_stats->mtime);
print "MOD_TIME = $timestamp_mod \n";

我想分享一下,以防其他人也遇到同样的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接