9

私はCSVファイルを読み取っていくつかの計算を行うPerlスクリプトに取り組んでいます。CSVファイルには次のような2つの列しかありません。

One Two
1.00 44.000
3.00 55.000

現在、このCSVファイルは非常に大きく、10MBから2GBまで可能です。

現在、サイズ700MBのCSVファイルを使用しています。このファイルをメモ帳で開こうとしましたが、Excelで開くソフトウェアがないようです。

CSVファイルの最後の1000行を読み、値を確認したいと思います。どうやってやるの?メモ帳やその他のプログラムでファイルを開くことができません。

Perlスクリプトを作成する場合は、ファイル全体を処理してファイルの終わりに移動し、最後の1000行を読み取る必要があります。

それへのより良い方法はありますか?私はPerlを初めて使用するので、提案をいただければ幸いです。

ネットで検索しましたが、次のようなスクリプトが利用できますFile::Tailが、Windowsで動作するかどうかわかりません。

4

11 に答える 11

29

File::ReadBackwardsモジュールを使用すると、ファイルを逆順に読み取ることができます。これにより、順序に依存しない限り、最後の N 行を簡単に取得できます。あなたがいて、必要なデータが十分に小さい場合(あなたの場合はそうあるべきです)、最後の1000行を配列に読み取ってからそれを読み取ることができますreverse

于 2008-11-19T19:58:31.460 に答える
11

* nixでは、tailコマンドを使用できます。

tail -1000 yourfile | perl ...

これにより、最後の1000行のみがperlプログラムに書き込まれます。

Windowsには、 gnuwin32パッケージとunxutilsパッケージの両方にtailユーティリティがあります。

于 2008-11-19T19:32:31.187 に答える
9

これはあなたの主な質問に接線的にのみ関連していますが、File::Tailなどのモジュールがプラットフォームで動作するかどうかを確認したい場合は、 CPAN Testersの結果を確認してください。CPAN 検索のモジュール ページの上部にあるリンクから、

ファイル末尾ヘッダー
(ソース: flickr.com )

マトリックスを見ると、テストされた Perl のすべてのバージョンの Windows で、実際にこのモジュールに問題があることがわかります。

ファイル末尾行列
(ソース: flickr.com )

于 2008-11-20T03:24:31.170 に答える
6

テールがなければ、Perl のみのソリューションはそれほど不合理ではありません。

1 つの方法は、ファイルの末尾からシークし、そこから行を読み取ることです。セリフが足りない場合は、最後からさらに探してやり直してください。

sub last_x_lines {
    my ($filename, $lineswanted) = @_;
    my ($line, $filesize, $seekpos, $numread, @lines);

    open F, $filename or die "Can't read $filename: $!\n";

    $filesize = -s $filename;
    $seekpos = 50 * $lineswanted;
    $numread = 0;

    while ($numread < $lineswanted) {
        @lines = ();
        $numread = 0;
        seek(F, $filesize - $seekpos, 0);
        <F> if $seekpos < $filesize; # Discard probably fragmentary line
        while (defined($line = <F>)) {
            push @lines, $line;
            shift @lines if ++$numread > $lineswanted;
        }
        if ($numread < $lineswanted) {
            # We didn't get enough lines. Double the amount of space to read from next time.
            if ($seekpos >= $filesize) {
                die "There aren't even $lineswanted lines in $filename - I got $numread\n";
            }
            $seekpos *= 2;
            $seekpos = $filesize if $seekpos >= $filesize;
        }
    }
    close F;
    return @lines;
}

PS より適切なタイトルは、「Perl で大きなファイルの末尾から行を読み取る」のようなものです。

于 2008-11-19T19:53:25.747 に答える
5

純粋な Perl で次のコードを使用して、クイック後方ファイル検索を作成しました。

#!/usr/bin/perl 
use warnings;
use strict;
my ($file, $num_of_lines) = @ARGV;

my $count = 0;
my $filesize = -s $file; # filesize used to control reaching the start of file while reading it backward
my $offset = -2; # skip two last characters: \n and ^Z in the end of file

open F, $file or die "Can't read $file: $!\n";

while (abs($offset) < $filesize) {
    my $line = "";
    # we need to check the start of the file for seek in mode "2" 
    # as it continues to output data in revers order even when out of file range reached
    while (abs($offset) < $filesize) {
        seek F, $offset, 2;     # because of negative $offset & "2" - it will seek backward
        $offset -= 1;           # move back the counter
        my $char = getc F;
        last if $char eq "\n"; # catch the whole line if reached
        $line = $char . $line; # otherwise we have next character for current line
    }

    # got the next line!
    print $line, "\n";

    # exit the loop if we are done
    $count++;
    last if $count > $num_of_lines;
}

このスクリプトを次のように実行します。

$ get-x-lines-from-end.pl ./myhugefile.log 200
于 2012-08-18T09:03:49.560 に答える
2
perl -n -e "shift @d if (@d >= 1000); push(@d, $_); END { print @d }" < bigfile.csv

とはいえ、UNIX システムでcygwincolinuxtail -n 1000をインストールすることができるという事実は、単純に納得できるはずです。

于 2008-11-19T19:50:32.367 に答える
1

私が信じているTie::Fileモジュールを使用できます。これにより、行が配列に読み込まれるように見えます。次に、配列のサイズを取得して、arrayS-ze-1000をarraySize-1まで処理できます。

Tie ::File

もう1つのオプションは、ファイル内の行数をカウントしてから、ファイルを1回ループし、numberofLines-1000で値の読み取りを開始することです。

$count = `wc -l < $file`;
die "wc failed: $?" if $?;
chomp($count);

これにより、(ほとんどのシステムで)行数がわかります。

于 2008-11-19T19:37:26.450 に答える
0

ファイルの行数がわかっている場合は、次のことができます。

perl -ne "print if ($. > N);" filename.csv

ここで、Nは$num_lines_in_file-$num_lines_to_printです。あなたはで行を数えることができます

perl -e "while (<>) {} print $.;" filename.csv
于 2008-11-19T19:47:14.933 に答える
0

モジュールは行く方法です。ただし、よりあいまいな CPAN モジュールが欠落している可能性のあるさまざまなマシンで実行したいコードを作成している場合があります。その場合、単に 'tail' して出力を Perl 内から一時ファイルにダンプしないのはなぜですか?

#!/usr/bin/perl

`tail --lines=1000 /path/myfile.txt > tempfile.txt`

インストールすると問題が発生する可能性がある場合は、CPAN モジュールに依存しないものがあります。

于 2012-10-30T11:30:06.577 に答える
-1

$FILESIZE [2GB?] を超えるメモリがある場合、テールに頼らずに、おそらくそうするでしょう。

my @lines = <>;
my @lastKlines = @lines[-1000,-1];

テールまたは関連する他の回答はseek()、これを進める方法です。

于 2008-11-19T20:42:08.457 に答える
-1

File::Tail を絶対に使用するか、別のモジュールを使用することをお勧めします。スクリプトではなく、モジュール (プログラミング ライブラリ) です。おそらくWindowsで動作します。誰かが言ったように、これは CPAN テスターで確認できます。または、多くの場合、モジュールのドキュメントを読んだり、試してみたりするだけで確認できます。

好みの答えとして tail ユーティリティの使用を選択しましたが、それは Windows では File::Tail よりも頭痛の種になる可能性があります。

于 2008-11-24T20:29:42.677 に答える