我在CSV文件中有以下列表,我的目标是根据每一行中的日期将此列表分为名为YYYY-Month
的目录。
NAME99;2018/06/13;12:27:30
NAME01;2018/06/13;13:03:59
NAME00;2018/06/15;11:33:01
NAME98;2018/06/15;12:22:00
NAME34;2018/06/15;16:58:45
NAME17;2018/06/18;15:51:10
NAME72;2018/06/19;10:06:37
NAME70;2018/06/19;12:44:03
NAME77;2018/06/19;16:36:55
NAME25;2018/06/11;16:32:57
NAME24;2018/06/11;16:32:57
NAME23;2018/06/11;16:37:15
NAME01;2018/06/11;16:37:15
NAME02;2018/06/11;16:37:15
NAME01;2018/06/11;16:37:18
NAME02;2018/06/05;09:51:17
NAME00;2018/06/13;15:04:29
NAME07;2018/06/19;10:02:26
NAME08;2018/06/26;16:03:57
NAME09;2018/06/26;16:03:57
NAME02;2018/06/27;16:58:12
NAME03;2018/07/03;07:47:21
NAME21;2018/07/03;10:53:00
NAMEXX;2018/07/05;03:13:01
NAME21;2018/07/05;15:39:00
NAME01;2018/07/05;16:00:14
NAME00;2018/07/08;11:50:10
NAME07;2018/07/09;14:46:00
在无需创建静态路由列表的情况下执行附加操作的最明智的方法是什么?
当前,我的程序仅基于YYYY-Month
将此列表写到名为localtime
的目录中,但每行都不执行任何操作。
#!/usr/bin/perl
use strict;
use warnings 'all';
use feature qw(say);
use File::Path qw<mkpath>;
use File::Spec;
use File::Copy;
use POSIX qw<strftime>;
my $OUTPUT_FILE = 'output.csv';
my $OUTFILE = 'splitted_output.csv';
# Output to file
open( GL_INPUT, $OUTPUT_FILE ) or die $!;
$/ = "\n\n"; # input record separator
while ( <GL_INPUT> ) {
chomp;
my @lines = split /\n/;
my $i = 0;
foreach my $lines ( @lines ) {
# Encapsulate Date/Time
my ( $name, $y, $m, $d, $time ) =
$lines[$i] =~ /\A(\w+);(\d+)\/(\d+)\/(\d+);(\d+:\d+:\d+)/;
# Generate Directory YYYY-Month - #2009-January
my $dir = File::Spec->catfile( $BASE_LOG_DIRECTORY, "$y-$m" ) ;
unless ( -e $dir ) {
mkpath $dir;
}
my $log_file_path = File::Spec->catfile( $dir, $OUTFILE );
open( OUTPUT, '>>', $log_file_path ) or die $!;
# Here I append value into files
print OUTPUT join ';', "$y/$m/$d", $time, "$name\n";
$i++;
}
}
close( GL_INPUT );
close( OUTPUT );
答案 0 :(得分:3)
这里没有理由要关心实际日期,也不需要使用日期函数。您想要基于数据中列之一的部分值来拆分数据。恰好是日期。
NAME08;2018/06/26;16:03:57 # This goes to 2018-06/ NAME09;2018/06/26;16:03:57 # NAME02;2018/06/27;16:58:12 # NAME03;2018/07/03;07:47:21 # This goes to 2018-07/ NAME21;2018/07/03;10:53:00 # NAMEXX;2018/07/05;03:13:01 # NAME21;2018/07/05;15:39:00 #
最简单的方法是对输入数据进行迭代,然后将每个年月组合的键放入带有键的哈希中。但是,您在谈论的是日志文件,它们可能很大,因此效率低下。
我们应该改用其他文件句柄。
use strict;
use warnings;
my %months = ( 6 => 'June', 7 => 'July' );
my %handles;
while (my $row = <DATA>) {
# no chomp, we don't actually care about reading the whole row
my (undef, $dir) = split /;/, $row; # discard name and everything after date
# create the YYYY-MM key
$dir =~ s[^(....)/(..)][$1-$months{$2}];
# open a new handle for this year/month if we don't have it yet
unless (exists $handles{$dir}) {
# create the directory (skipped here) ...
open my $fh, '>', "$dir/filename.csv" or die $!;
$handles{$dir} = $fh;
}
# write out the line to the correct directory
print { $handles{$dir} } $row;
}
__DATA__
NAME08;2018/06/26;16:03:57
NAME09;2018/06/26;16:03:57
NAME02;2018/06/27;16:58:12
NAME03;2018/07/03;07:47:21
NAME21;2018/07/03;10:53:00
NAMEXX;2018/07/05;03:13:01
NAME21;2018/07/05;15:39:00
由于您已经知道如何创建目录,因此我已经跳过了创建目录的部分。
如果您的数据行不是连续的,则此代码也将起作用。这不是最有效的方法,因为句柄的数量将增加您拥有的更多数据,但是只要您同时没有100个句柄就没关系了。
注意事项:
chomp
是因为您不关心使用最后一个字段。split
之后分配所有值,因为您不需要关心它们。 undef
来丢弃它们。open
和 lexical 文件句柄。 {}
中的print { ... } $row
来告诉Perl这也是我们正在打印的句柄。参见http://perldoc.perl.org/functions/print.html。