【问题标题】:Open a directory and sort files by date created打开目录并按创建日期对文件进行排序
【发布时间】:2013-04-12 07:47:00
【问题描述】:

我需要在文件创建时打开目录并对其进行排序。我可以找到一些讨论,使用 Perl、排序和文件的标签,根据修改日期对文件进行排序。我认为这是比按创建日期排序更常见的需求。我使用 Perl。以前有一些关于 Perl 以外的其他语言(例如 php 或 java)按创建日期排序的帖子。

例如,我需要执行以下操作:

opendir(DIR, $ARGV[0]);                             
my @files = "sort-by-date-created" (readdir(DIR)); 
closedir(DIR);

do things with @files...

CPAN 有一个关于排序命令的页面,但对我来说不是很容易访问,而且我在页面上找不到“日期”或“创建”字样。

作为对编辑的回应,我应该说我使用的是 Mac、OS 10.7。我知道在 Finder 中,有一个按创建日期排序的选项,因此必须有某种指示以某种方式附加到该系统中的文件的创建日期。

作为对答案的回应,这里是尝试对文件进行排序的脚本的另一个版本:

#!/usr/bin/perl
use strict; use warnings;

use File::stat; # helps with sorting files by ctime, the inode date that hopefully can serve as creation date

my $usage = "usage: enter name of directory to be scanned for SNP containing lines\n";
die $usage unless @ARGV == 1;

opendir(DIR, $ARGV[0]);                             #open directory for getting file list
#my @files = (readdir(DIR));
my @file_list = grep ! /^\./, readdir DIR; 
closedir(DIR);  

print scalar @file_list."\n";

for my $file (sort {
        my $a_stat = stat($a);
        my $b_stat = stat($b);
        $a_stat->mtime <=> $b_stat->mtime;
    }  @file_list ) {
    say "$file";
}

【问题讨论】:

  • 什么操作系统?许多文件系统没有创建日期,只有修改日期。
  • 操作系统是Mac OS 10.7。
  • 为什么不直接使用文件测试操作符呢? sort { -C $a &lt;=&gt; -C $b } @files

标签: perl file sorting


【解决方案1】:

您可以通过向sort 函数提供子例程或代码块来自定义排序顺序。

  • 在这个子块或块中,您需要使用特殊变量$a$b,它们表示比较@array 中的值。
  • 子或块需要返回一个小于、等于或大于0的值来指示$a是小于、等于还是大于$b(分别)。
  • 您可以使用特殊的比较运算符(&lt;=&gt; 用于数字,cmp 用于字符串)为您执行此操作。

所以默认排序sort @numbers等价于sort {$a &lt;=&gt; $b} @numbers

在按创建时间排序的情况下,您可以使用stat 函数来获取有关文件的信息。它返回有关文件的一系列信息,其中一些可能不适用于您的平台。文件的最后修改时间通常是安全的,但创建时间不是ctime(它返回的第 11 个值)尽可能接近(它表示 *nix 上的 inode 更改时间,win32 上的创建时间),它表示为自 epoch 以来的秒数,这很方便,因为这意味着您可以进行简单的数字排序。

my @files = sort {(stat $a)[10] <=> (stat $b)[10]} readdir($dh);

我不确定您是否也想过滤掉这些目录。如果是这种情况,您可能还想使用grep

【讨论】:

  • 我需要按创建日期或时间排序,而不是按修改时间排序。这似乎是一个更常见的任务,但就我而言,我需要按创建时间排序。
  • 我不明白“过滤掉目录”。这是什么意思?在文件排序期间忽略它们?
  • “过滤器”是指从您的列表中排除目录。
  • Mac OS X 支持索引节点更改时间,文件创建时间也是如此。困难在于 Perl 中的文件创建时间。
  • 问题是一些文件系统就是不保存这些信息
【解决方案2】:

我需要打开目录并按文件的创建时间对文件进行排序。

你不能。 创建时间根本不存在。 *nix 类操作系统跟踪三个时间元素:

  • mtime:这是文件最后一次修改的时间。
  • atime:这是文件上次访问的时间。
  • ctime:这是上次修改inode 的时间。

在 Unix 中,某些文件信息存储在 inode 中。这包括您在获取文件的 Perl stat 时看到的各种内容。这是用户名、文件大小、它所在的设备、链接数,讽刺的是,mtimeatimectime 时间戳。

为什么没有创建时间?因为你会如何定义它?如果我移动文件怎么办?如果有新的创建时间(顺便说一下,ctime 不会随着移动而改变)。如果我复制文件怎么办?新副本是否应该有新的创建时间?如果我做了一个副本,然后删除了原件怎么办?如果我编辑了一个文件怎么办?如果我用我的编辑更改了文件中的所有内容呢?还是我编辑了文件,然后将其重命名为全新的名称?

即使在具有文件创建时间的 Windows 上,也不会真正跟踪文件创建。它仅跟踪创建目录条目的时间,这有点像ctime 所做的。而且,您甚至可以通过 Windows API 修改这个创建时间。我怀疑 Mac 的文件创建时间是 HFS 文件系统的遗留物,实际上并没有像第一次创建目录条目的时间那样指向文件创建时间。


正如其他人指出的那样。您可以在排序例程中添加一段代码,说明您希望如何排序。这是一个快速的例子。请注意,我使用 File::stat,它为旧的 stat 命令提供了一个很好的 by name 界面。如果我使用旧的 stat 命令,我会得到一个数组,然后必须找出我想要的项目在数组中的位置。在这里,stat 命令给了我一个stat 对象,我可以使用mtimeatimectime 方法 来拉出右边时间。

我还使用&lt;=&gt;,它是专门为sort 命令块制作的比较运算符。

排序命令为您提供两个项目$a$b。您使用这两个项目来确定您想要什么,然后使用&lt;=&gt;cmp 来判断$a 是否更大,$b 是否更大,或者它们的大小相同。

#! /usr/bin/env perl

use 5.12.0;
use warnings;

use File::stat;

my $dir_name = shift;

if ( not defined $dir_name ) {
    die qq(Usage: $0 <directory>);
}

opendir(my $dir_fh, $dir_name);

my @file_list;
while ( my $file = readdir $dir_fh) {
    if ( $file !~ /^\./ ) {
        push @file_list, "$dir_name/$file"
    }
}
closedir $dir_fh;

say scalar @file_list;

for my $file (sort {
        my $a_stat = stat($a);
        my $b_stat = stat($b);
        $a_stat->ctime <=> $b_stat->ctime;
    }  @file_list ) {
    say "$file";
}

【讨论】:

  • 关于“inode”...所以,在 Finder 窗口中,当我选择按“创建日期”排列文件时,我实际上是在要求计算机按“ctime”sort 文件,对吗?
  • 另外,当您使用use 5.12.0; 时,是否启用say 命令?还是use 5.12.0; 在这里有其他或更通用的用途?
  • 当您使用use 5.12.0(或更高版本)时,您会启用所有各种新功能,此外还会自动打开strict。我不知道为什么警告也不会自动打开,但事实并非如此。
  • Perl 最初是为 Unix 编写的,因此它具有 Unix 偏见。对于这些类型的极端情况,您需要查看perlport。 Perlport 在 Windows ctime=Win32 创建时间上说,但在 MacOS X w/HFS+ 上是沉默的。 Mac 联机帮助页用处不大。有一个获取 creation-date 的 MacOSX::File::Info CPAN 模块。不幸的是,它不会安装在我的 MacBook Pro 上。如果您可以使用 MacOSX::File::Info,则可以使用它来代替 File::stat,或者至少将 File::stat 上的 ctime 与 MacOSX::File:Info 上的创建时间进行比较
  • 嗨,当我尝试您的脚本行时,我得到了这个:无法在 snpParsing.pl 第 29 行对未定义的值调用方法“mtime”。
【解决方案3】:

OS X 将创建日期存储在 Mac 特定的元数据中,因此标准 Perl 文件系统函数不知道它。您可以使用MacOSX::File 模块来访问此信息。

【讨论】:

  • 如果我切换到 PC 会怎样?在这种情况下,我可以用 perl 做什么?
  • 我通过谷歌搜索找到了该模块。我想你也可以这样做。
  • MacOSX::File 模块最后一次更新是在 2005 年。我刚刚尝试在 Mac OS X 10.7.5 (Perl 5.16.2) 上安装它,但编译失败。可惜......它可能可以修复,但我还没有这样做。我使用自制版本的 GCC 和自制的 Perl;这可能是问题所在,但我收到的错误消息是/Developer/Headers/FlatCarbon/strings.h:1:2: warning: #warning Strings.h is not available on Mac OS X [-Wcpp]
  • 糟糕。刚刚查看了指向我的博客,它是从 2002 年开始的!
  • Mac::File 依赖于旧的 Carbon 框架,但 Mac OS X 不再支持 Carbon 框架。 Carbon 框架可以帮助开发人员将他们的程序从旧的 System 7/8/9 移植到 MacOS X。但是,Apple 在几个 OS X 版本之前停止支持它。
【解决方案4】:
#!/usr/bin/env perl
use strict;
use warnings;
opendir(DIR, $ARGV[0]);
chdir($ARGV[0]);
my @files = sort { (stat($a))[10] <=> (stat($b))[10] } (readdir(DIR));
closedir(DIR);
print join("\n",@files);

stat 为您提供各种文件状态信息。其中字段 10 是 ctime(在支持它的文件系统上),它是 inode 更改时间(不是创建时间)。

【讨论】:

  • ctimeinode change time,而不是 creation time
  • 另外,您对stat() 的论点是错误的。他们应该是$ARGV[0].'/'.$a$ARGV[0].'/'.$b
  • @barman :我添加了 chdir 来说明这一点。 '/' 不是通用目录分隔符。并添加了关于 ctime 不是创建时间的评论。
【解决方案5】:

Mojo::File 带来了一些有趣且易读的方法。

#!/usr/bin/env perl
use Mojo::File 'path';

my $files_list = path( '/whatever/dir/path/' )->list;

# Returns an array of Mojo::File
my @files = sort { $a->stat->ctime <=> $b->stat->ctime }
  map { $_ }  $files_list->each;

# Returns an array of paths sorted by modification date (if needed)
my @paths = map { $_->realpath->to_string } @files;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-30
    • 2021-07-09
    • 2012-02-18
    • 1970-01-01
    相关资源
    最近更新 更多