Разделить мой вывод на несколько файлов - PullRequest
0 голосов
/ 05 июля 2018

У меня есть следующий список в файле 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 голосов
/ 05 июля 2018

Нет причин беспокоиться о фактической дате или вообще использовать функции даты здесь. Вы хотите разделить ваши данные на основе частичного значения одного из столбцов в данных. Так случилось, что это дата.

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

Я пропустил часть о создании каталога, поскольку вы уже знаете, как это сделать.

Этот код также будет работать, если ваши строки данных не являются последовательными. Это не самый эффективный метод, так как количество дескрипторов будет увеличиваться по мере увеличения количества данных, но если у вас их нет одновременно, это не имеет значения.

Примечания:

  • Вам не нужно chomp, потому что вам не нужно работать с последним полем.
  • Вам не нужно присваивать все значения после split, потому что вы не заботитесь о них.
  • Вы можете отказаться от значений, присвоив их undef.
  • Всегда используйте дескрипторы файлов open и с тремя аргументами .
  • {} в print { ... } $row необходимы, чтобы сказать Perl, что это ручка, которую мы печатаем тоже. См http://perldoc.perl.org/functions/print.html.
...