-1

数行からなる大きなファイルがあります。サイズに基づいてファイルをチャンクに分割する必要があります(たとえば、1つのファイルを4つの部分に分割する)が、2つの部分に分割する行は必要ありません(各行はチャンクに完全に存在する必要があります)。処理する各スレッドと処理後、すべてのチャンクを再度アセンブルします。主にファイルの内容の処理時間を短縮したい(ファイルのテキストを少し置き換えます)。

この問題を解決するための最良のアプローチは何でしょうか。私が念頭に置いているのは、サイズに基づいてチャンクの最後のバイトまで到達することです。最後の文字が行の終わりでない場合は、行の終わりを取得してその部分を格納するまで読み取りを続けます。

同じ上で提案やより良いアルゴ。あなたの助けに感謝。

編集:

また、内容全体が変数に含まれていますが、変数の特定のバイトに到達するにはどうすればよいですか?

編集:ユーザーが提案したように、適切な英語と問題の説明を使用してもう1つ編集します。

問題文:

私はperlの変数(スカラー)にいくつかのデータ(htmlページのコンテンツ全体)を持っています$ strを想定し、データはいくつかの行(約1762899行)で構成されていますスカラーのデータをより小さなチャンクに分割する必要があります(いくつかの元の行)$ str1、$ str2、$ str3、$ str4のような長さに基づいて、これらの変数に参加すると、完全なコンテンツが取得されます。

要件:

上記のstrが必要なので、スレッドに渡すことができます。すべてのスレッドが完了したら、これらすべてを結合して、コンテンツ全体を元に戻します。

私の理解:

substrを使用してcharからcharにデータを取得しますが、最初に、substrで取得する最後のcharが改行文字であることを確認する必要があります。この場合のアプローチ方法は?

解決策が必要です。ありがとう。

4

5 に答える 5

1

このアルゴリズムを使用して、ソース HTML をかなり均等な数の部分に分割し、行の境界で分割することができます。

このように勝手に分割されたデータでは処理ができないのではないかと心配ですが、問題があればまた質問してください。

use strict;
use warnings;

my $html;
$html .= $_ x 10 . "\n" for 'A' .. 'Z';

use constant PARTITIONS => 4;

my @start;
push @start, $-[0] while $html =~ /^/gm;
push @start, length $html;
my $n = @start;
my @parts = map $start[$_ * ($n-1) / PARTITIONS], 0 .. PARTITIONS;

for my $i (0 .. $#parts-1) {
  my ($start, $size) = ($parts[$i], $parts[$i+1] - $parts[$i]);
  print substr $html, $start, $size;
  print '-' x 10 . "\n";
}

出力

AAAAAAAAAA
BBBBBBBBBB
CCCCCCCCCC
DDDDDDDDDD
EEEEEEEEEE
FFFFFFFFFF
----------
GGGGGGGGGG
HHHHHHHHHH
IIIIIIIIII
JJJJJJJJJJ
KKKKKKKKKK
LLLLLLLLLL
MMMMMMMMMM
----------
NNNNNNNNNN
OOOOOOOOOO
PPPPPPPPPP
QQQQQQQQQQ
RRRRRRRRRR
SSSSSSSSSS
----------
TTTTTTTTTT
UUUUUUUUUU
VVVVVVVVVV
WWWWWWWWWW
XXXXXXXXXX
YYYYYYYYYY
ZZZZZZZZZZ
----------
于 2012-05-24T14:16:45.187 に答える
0

素朴な(しかしおそらく十分に効率的な)解決策:

4 つの子プロセスを fork し、入力ファイルを 1 行ずつ読み取り、各行を子プロセスに送信します。出力に使用するファイル名を子プロセスに伝えます。

作業が完了すると、親プロセスは結果を再度集計できます。

于 2012-05-24T07:50:33.117 に答える
0

あなたの質問は私にとって十分に明確ではありません。まだいくつかの提案。

などの標準の UNIX ツールを使用できますsplit --lines=10000

perl を使用する必要がある場合はwhile、以下に基づいて を分割できます。

open(my $fh, "<", "input.txt")
                       or die "cannot open < input.txt: $!";
while ( <$fh> ) {
    # controll count of lines you need and open/close new FH if needed...
    print $nfh $_;
}
close($fh);

あなたの編集について:バイトまたは文字に到達する必要がありますか? あなたの質問はテキストと文字列に関するものなので、文字が必要だと思います。その後、使用できますsubstr

于 2012-05-24T08:09:45.447 に答える
0

それを解決するためのコードを考えてみました。以下のコードを見つけてください。

    #!/usr/bin/perl

    use strict;

    ### File contents to be broken in pieces ###
    open(FH, "<index.html");

    ### slurp whole file in scalar ###
    my $text = do { local $/; <FH> };

    ### Length of file ###
    my $length = length $text;
    print "length=$length\n";

    #### We will create 6 threads so divide it into 6 parts ###
    my $chunk_sz = int($length/6);
    print "chunk size=$chunk_sz\n";

    ### Lets have the chunks into some var and check the chunk end with proper new line char ###
    my $start = 0;
    my @res;

    for(my $i = 0; $i <= 5; $i++)
    {
        #print "start is : $start\n";
        my $chunk;
        my $var = 0;

        ### If it's last chunk, take all contents ###
        if($i == 5)
        {
            $chunk_sz = $length - $start;
            $chunk = substr($text, $start, $chunk_sz);
        }
        else
        {
            $chunk = substr($text, $start, $chunk_sz);
        }
        START:
        my $last_ch = chop($chunk);    ### If last char is not new line(\n) char find it and save the chunk ###

    while($last_ch !~ /\n/ && $i != 5)
    {
        $var += 1;
        $chunk = substr($text, $start, $chunk_sz+$var);
        goto START;
    }
    ### Start from the last chunk char + 1 ###
    $start += $chunk_sz+$var+1;
    $res[$i] = $chunk."\n";
}

## Further code to process the chunk in threads goes here ###

改善または修正のための提案はありますか?

于 2012-05-25T04:52:47.003 に答える
0

この回答は、このユーザーには役に立たないかもしれませんが、100万行のファイルをそれぞれ10万行の複数のファイルに分割するperlコードを探していました。複数の投稿と試行錯誤を読んだ後、このコードを共有しました。いいね!

#!/bin/perl -s
#
# $Header$
# $Log$
use File::Basename;
use File::stat;
use English;
use Time::Local;
use Data::Dumper;
use IO::Handle;
use Fcntl;                             # For O_RDWR, O_CREAT, etc.
use POSIX qw(strftime);
use bigint;
use strict;

$\ = "\n";    # set output record separator

print "Starting program ...";



#
#  Get the interface directory path
#
my $ScriptName = $0;
my $ScriptDirPath = `dirname $ScriptName`;
chop($ScriptDirPath);


my $LOAD_INP_FILE = $ScriptDirPath . "03g_loadInp.txt";
my $LOAD_CHUNK_FILE = $ScriptDirPath . "04g_loadInp_00000000.txt";

my $source = $LOAD_INP_FILE;
my $lines_per_file = 100000;

open (my $FH, "<$source") or die "Could not open source file. $!";
open (my $OUT, ">$LOAD_CHUNK_FILE") or die "Could not open destination fil
+e. $!";

#this is line counter
my $i = 0;

print "Creating new $LOAD_CHUNK_FILE ...";

my $line;
while ($line = <$FH> ) {
    chop $line;
    print $OUT $line;
    $i++;

    if ($i % $lines_per_file == 0) {
        close($OUT);
        my $FHNEW = sprintf("%08d", $i);
        my $LOAD_CHUNK_FILE_NEW = $ScriptDirPath . "04g_loadInp_${FHNEW}.txt";
        open ($OUT, ">$LOAD_CHUNK_FILE_NEW") or die "Could not open destinatio
+n file. $!";
        print "Creating new $LOAD_CHUNK_FILE_NEW ...";
    }
}


print "Ending program ...";
exit 0;

#
#  End of Main Program
#
于 2015-10-16T14:04:06.917 に答える