逐行读取文件而不将整个文件加载到内存中

时间:2014-04-26 22:22:58

标签: mysql perl bash sqlite bigdata

我正在使用50 Gb MySQL导出文件,并在其上执行脚本操作列表以转换为SQLite3可加载表单(我从这里得到了引导:script to convert mysql dump sql file into format that can be imported into sqlite3 db)。我还没有研究过MySQL转储的结构,数据来自第三方。我可以看到它已创建表并插入到语句中,但考虑到大小,很难手动读取并理解结构。 由于大小原因,通过管道传输文件将无法正常工作。也是一个bash脚本,用于加载文件,然后逐行处理,例如

while read line
<do something>

抱怨说它是内存不足。

所以我尝试使用awk或sed(两者都工作)选择每一行,将该行写入文件,然后将其传递给perl脚本列表。这是我正在使用的awk脚本

$ awk -vvar="$x" 'NR==var{print;exit}' file > temp

其中x保存行号,然后temp通过perl命令发送,最后附加到输出文件。

然而,尽管最初速度很快,但它会从一开始就不断迭代越来越多的行,因此会很快减速。大约有40,000行。

有没有人使用过类似的东西?有没有更快的方法呢?

1 个答案:

答案 0 :(得分:3)

一次只处理一行:

while read -r line
do
    echo "$line" > temp
    …process temp with Perl, etc…
done < file

至少这不会显示读取文件的二次行为,这就是awk脚本的作用。 它只读取一次大文件,这是Big-O表示法中的最佳性能(在常数因子内)。

正如你所说,如果导致bash出现问题,那么你应该使用Perl来读取每一行。在50 GiB数据中有40,000行,每行有大约1¼MiB的数据。这不太可能导致Perl出现任何问题,尽管它可能会导致Bash问题。您可以修改现有的Perl一次读取一行,也可以使用一个简单的包装器Perl脚本来执行上面的Bash脚本。

wrapper.pl

假设您当前的处理脚本名为script.pl

#!/usr/bin/env perl
use strict;
use warnings;

my $file = "temp";

while (<>)
{
    open my $fh, ">", $file or die;
    print $fh $_;
    close $fh;
    system "perl", "script.pl", $file;
}

未经测试的代码

调用:

perl wrapper.pl <file >output