手动输入数据会使数据库被包含多个换行符的记录污染。对于只有一列的 60GB 巨大平面文件中开头和结尾处用双引号分隔的良好记录,它们应该始终只跨越一行,如下所示:
“现在可以获得许多线粒体、许多原核生物和一些核基因组的完整序列。”
对于不良记录,它们跨越无限数量的多行,如下所示:
“当前吸烟与高风险呈强烈负相关。
调整伴随风险因素后的模式。相对于从不
吸烟者,当前吸烟者患高风险的可能性明显降低
图案。 ”
这些多行记录禁止 UNIX 命令进行下游文件分割split
。split
无法智能地将这些多行识别为单个记录,这可能导致将单个记录拆分为单独的文件。下面的 Perl 太慢了,无法在分割之前先合并这个大文件的坏记录行,因为等待超过 2 小时后 $count 无法打印。
$file=$ARGV[0];
open(INFO, $file) or die("Could not open $file.");
open(OUT, ">out") or die("Could not open $file.");
$mergedline = "";
$count=0;
foreach $line (<INFO>) {
print $count++;
if ($line =~ /^".*"\n$/) {
print OUT $line;
$mergedline = "";
next;
} elsif ($line =~ /"\n$/) {
print OUT $mergedline;
$mergedline = "";
next;
} else {
chomp $line;
$mergedline .= $line;
}
}
close(INFO);
有什么方便的 UNIX 命令可以解决这个问题,使输出文件“干净”,只有单行记录可以处理split
?
sed
似乎是一个选项,但以下帖子都没有回答这个问题:
https://stackoverflow.com/questions/11290616/sed-conditional-merge-of-multiple-lines
http://www.unix.com/shell-programming-and-scripting/80633-sed-combining-multiple-lines-into-one.html
因为他们发帖的模式太有规律、太恒定了。
答案1
仅用于sed
连接分割线
sed ':a
/".*"$/b
N;s/\n/ /;ba' input >> output
在我的系统上处理一个 10 MB 的文件需要 6 秒。对于 60 GB,这将是 10 小时。
bbe
有点快
bbe -b '/"/:/"/' -o output -e 'y/\n/ /' input
但仍然需要 4 秒。
恐怕这些脚本语言不是在极大文件上表现良好的工具。写一个小程序怎么样C
?
答案2
使用示例gawk
:
awk 'BEGIN {RS = "\"\n"} {++n; print $0"\""> n".txt"}' input
input
这表示按照任意顺序分割文件,"
后跟换行符 ( \n
)。这将忽略不立即跟在引号后面的换行符,从而保留多行记录。在此示例中,输出写入文本文件,但如果删除该> n".txt"
部分,则可以将记录发送到管道。
答案3
Perl
由于for
使用循环来读取文件,因此您的速度很慢。您确实应该使用while
循环,因为for
循环一次性将整个文件加载到内存中。这就是为什么打印 $count 需要很长时间的原因。
perl -ne '
print,next if /^".*"$/m or /"$/m;
chomp, $_ .= <>, redo unless eof;
' gene.data