2011-01-31 6 views
3

私はストーリーの数を含む大きなテキストファイル(約10 GB)を持っています。各話はマーカー$$で始まります。以下はこのファイルのサンプルです:大きなテキストファイルをレコードを切り捨てることなくほぼ均等なサイズに分割するにはどうすればよいですか?

$$ 
AA This is story 1 
BB 345 

$$ 

AA This is story 2 
BB 456 

このファイルを約250 MBのサイズに分割します。しかし、ストーリーのどれも2つの異なるファイルに分割されるべきではありません。

誰かがこれについてUnixまたはPerlコードを手伝ってくれますか?

答えて

1

csplitです。 splitと同じですが、パターンに基づいています。 C++で

代替(試験せず):

#include <boost/shared_ptr.hpp> 
#include <sstream> 
#include <iostream> 
#include <fstream> 
#include <string> 

void new_output_file(boost::shared_ptr<std::ofstream> &out, const char *prefix) 
{ 
    static int i = 0; 
    std::ostringstream filename; 
    filename << prefix << "_" << i++; 
    out.reset(new std::ofstream(filename)); 
} 

int main(int argc, char **argv) 
{ 
    std::ifstream in(argv[1]); 
    int i = 0; 
    long size = 0; 
    const long max_size = 200 * 1024 * 1024; 
    std::string line; 
    boost::shared_ptr<std::ofstream> out(NULL); 
    new_output_file(out, argv[2]); 
    while(in.good()) 
    { 
     std::getline(in,line); 
     size += line.length() + 1 /* line termination char */; 
     if(size >= max_size && line.length() && line[0] == '$' && line[1] == '$') 
     { 
      new_output_file(out, argv[2]); 
      size = line.length() + 1; 
     } 
     out << line << std::endl; 
    } 
    return 0; 
} 
+1

全く問題はないようです。 – ysth

+0

それは確かです。分割基準として正規表現を指定することができます。質問者が/ \ $ \ $ /に設定すると、 'csplit'は彼らが望むことをするはずです。 – CanSpice

+0

@CanSplice:目標は正規表現に分割するのではなく、\ $ \ $ \ nで区切られたチャンクを分割せずに250Mbごとに分割することです。 csplitはそれをしません。 – ysth

5
use strict; 
use warnings; 
use autodie; 

$/ = "\$\$\n"; 
my $targetsize = 250*1024*1024; 
my $fileprefix = 'chunk'; 
my $outfile = 0; 
my $outfh; 
my $outsize = 0; 
while (my $story = <>) { 
    chomp($story); 
    next unless $story; # disregard initial empty chunk 
    $story = "$/$story"; 

    # no file open yet, or this story takes us farther from the target size 
    if (! $outfile || abs($outsize - $targetsize) < abs($outsize + length($story) - $targetsize)) { 
     ++$outfile; 
     open $outfh, '>', "$fileprefix$outfile"; 
     $outsize = 0; 
    } 

    $outsize += length($story); 
    print $outfh $story; 
} 
+0

私はまだこのコードをテストしていませんが、サイズ10GBの巨大なファイルを読むのはここで可能ですか? wouldntプログラムは「システムがメモリ不足」と言うエラーを投げますか? – Man

+0

@Man:いいえ、このコードは、一度に1つのストーリーしかメモリにはありません。 – ysth

+0

ありがとう、ちょうどここでautodieの使用が何であるか知りたいのですか?私はそれが私のシステムにインストールされていないので、行をコメントしましたが、今ではプログラムはchunk1の全入力ファイルを書いています.. – Man

1

Iはysthのコードを変更し、それが作業を発見しました。あなたが思っていることをお勧めします、あなたはこれを改善するために修正することができます。

use strict; 
use warnings; 

my $targetsize = 50*1024*1024; 
my $fileprefix = 'chunk'; 
my $outfile = 0; 
my $outsize = 0; 
my $outfh; 
my $temp=''; 
while (my $line = <>) { 
    chomp($line); 
    next unless $line; 
    # discard initial empty chunk 
    if($line =~ /^\$\$$/ || $outfile == 0){ 
     $outsize += length($temp); 
     if ($outfile == 0 || ($outsize - $targetsize) > 0) { 
       ++$outfile; 
       if($outfh) {close($outfh);} 
       open $outfh, '>', "$fileprefix$outfile"; 
       $outsize = 0; 
     } 
     $temp=''; 
    } 
    $temp = $temp.$line; 
    print $outfh "$line\n"; 
} 
+0

openは、ファイルハンドルが開いていても自動的にcloseを行いますが、明示的なcloseは害を受けません。あなたはその長さに対して$ tempしか使用していません。代わりに各行に$ outsizeを追加するだけで済みます。あなたは物語の中の空の行を削除しています - それは意図的ですか?あなたが追加している長さに改行は含まれていないので、ややずれています。あなたはchompとprintの\ nを取り除き、代わりに$ line eq "\ n"と答えることができます。 – ysth

関連する問題