将我的输出分成多个文件

时间:2018-07-05 14:39:22

标签: perl date split

我在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的目录中,但每行都不执行任何操作。

Perl

#!/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 );

1 个答案:

答案 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