-1

我有一个由几行组成的大文件。我需要根据大小将文件分成块(比如将 1 个文件分成 4 个部分),但我不需要将行分成 2 个部分(每行应该完全存在于一个块中),然后将这些块给每个要处理的线程和处理后我将再次重新组装所有块。主要是我想减少文件内容的处理时间(我在文件文本中做了一些替换)。

解决这个问题的最佳方法是什么?我想到的是根据大小到达块的结束字节,如果结束字符不是行尾,请继续阅读,直到我得到行尾并存储该部分。

任何建议或更好的算法都相同。感谢你的帮助。

编辑:

此外,整个内容都在一个变量中,我怎样才能到达变量中的某个字节?

编辑:根据用户的建议,使用适当的英语和问题陈述再进行一次编辑:

问题陈述:

我在 perl 中的变量(标量)中有一些数据(整个 html 页面内容)假设 $str,数据由几行组成(大约 1762899 行)我需要将标量中的数据分成更小的块(有一些来自原始的行)基于某种长度,如 $str1、$str2、$str3、$str4,如果我加入这些 var,我会得到完整的内容。

要求:

我需要上面的 strs,所以我可以把它们交给线程,在所有线程完成后,我将加入所有这些以取回全部内容。

我的理解:

我将使用 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

一个天真的(但可能足够有效)的解决方案:

fork 4 个子进程,逐行读取输入文件并将每一行发送给一个子进程。告诉子进程将哪个文件名用于输出。

工作完成后,父进程可以再次聚合结果。

于 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

这个答案可能对这个用户没有用,但我一直在寻找 perl 代码,它将一百万行文件分成多个文件,每个文件有 100K 行。在阅读了多篇文章和反复试验后,我得到了这个代码来分享。喜欢的请点赞!

#!/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 回答