我有一个相当大的数据集(10K文件,每个文件有20K行)。我需要交换文件和行,(给自己20K文件,每个文件有10K行)。
我有一个解决方案,将它全部组合成一个大表,然后用剪切提取列..但剪切花费的时间太长(扫描4GB文件10K次并不是很快,即使文件是坐在缓存里。)
所以我在awk中写了一篇(令人惊讶的简单)一次性通过:
awk '{ print >> "times/"FNR".txt" }' posns/*
这可以完成工作,但也很慢(每个输入文件大约10秒)。我的猜测是它正在进行场分离,尽管事实上我根本不需要它。有没有办法禁用该功能以加快速度,或者我将不得不用另一种语言编写解决方案?
如果它有帮助,虽然我更喜欢一般解决方案,但每个文件中的每一行都是%d %lf %lf
形式,因此在这种情况下,行最多为21个字节(浮点数都小于100) ,整数是0或1)。
答案 0 :(得分:1)
你可以尝试不同的awk。我听说mawk比其他awk快,GNu awk有一些性能改进,这意味着它可能比你使用的任何东西运行得更快。如果你将字段分隔符设置为记录分隔符,那么每行只会有一个字段,所以如果你正确地将字段拆分作为问题,那么可能会加快它的速度。此外,您使用了错误的重定向运算符 - 您应该使用“>”不是“>>”和字符串连接很慢所以我建议只打印到编号的文件,然后重命名它们。
这样的事情:
cd times
awk -F'\n' '{ print > FNR }' ../posns/*
for f in *
do
mv -- "$f" "${f}.txt"
done
cd ..
您可能希望首先在虚拟目录上测试它。
在这个帖子中的其他评论可能是同时打开这么多文件就是问题,你可以根据文件名中的某些模式对子组进行操作吗?例如,如果您的posns文件都以数字开头:
cd times
rm -f *
for ((i=0; i<=9; i++))
do
awk -F'\n' '{ print >> FNR }' ../posns/"$i"*
for f in *
do
mv -- "$f" "${f}.txt"
done
done
cd ..
请注意,在这种情况下,您需要首先删除输出文件。我确信有一种更好的方法可以对文件进行分组,但是你需要告诉我们是否有命名约定。
答案 1 :(得分:1)
我不知道这是否比awk更快,但这是一个完成任务的perl脚本:
#!/usr/bin/perl
use strict;
use warnings;
my $line=0;
foreach(@ARGV){
open (MYINFILE, $_);
$line=0;
while(<MYINFILE>){
$line++;
open (MYOUTFILE,">>times/$line.txt");
print MYOUTFILE $_;
close (MYOUTFILE);
}
}
答案 2 :(得分:0)
对于split来说,这听起来是完美的工作;)
find posns -type f -exec split -l 10000 {} \;
您可以使用-a
和-d
选项来自定义结果文件后缀。
<强>解释强>
find posns -type f
:在目录posns
-exec ... \;
:对于找到的每个结果,请执行以下命令...
split -l 10000 {}
:当{}
与-exec
结合使用时,split -l 10000
就是将结果替换为的地方。 {{1}}将输入文件拆分为每个最多10k行的块。答案 3 :(得分:0)
最终我给出了漂亮的shell方法,并在C中写了另一个版本。很遗憾,它不漂亮,但速度提高了三个数量级以上(总运行时间为43秒,而估计为28秒)给定预缓存数据的awk方法的小时数)。它需要更改ulimit以允许足够的打开文件,如果你的行长于LINE_LENGTH,它将无法正常工作。
尽管如此,它的运行速度比下一个最佳解决方案快2300倍。
如果有人偶然发现这个任务,我们就会这样做。请小心并检查它是否真的有用。
#include <stdio.h>
#include <stdlib.h>
#define LINE_LENGTH 1024
int main(int argc, char* argv[]) {
int fn;
int ln;
char read[LINE_LENGTH];
int fmax=10;
int ftot=0;
FILE** files=malloc(fmax*sizeof(FILE*));
char fname[255];
printf("%d arguments\n", argc);
printf("opening %s\n",argv[1]);
FILE* open = fopen(argv[1],"r");
for(ln=0;fgets(read,LINE_LENGTH,open); ln++) {
if(ln==fmax) {
printf("%d has reached %d; reallocing\n",ln,fmax);
fmax*=2;
files=realloc(files,fmax*sizeof(FILE*));
}
sprintf(fname, "times/%09d.txt",ln);
files[ln]=fopen(fname,"w");
if(files[ln]==0) {
fprintf(stderr,"Failed at opening file number %d\n",ln);
return 1;
}
fprintf(files[ln],"%s",read);
}
ftot=ln;
fclose(open);
for(fn=2;fn<argc;fn++) {
printf("working on file %d\n",fn);
open=fopen(argv[fn],"r");
for(ln=0;fgets(read,LINE_LENGTH,open); ln++) {
fprintf(files[ln],"%s",read);
}
fclose(open);
}
for(ln=0;ln<ftot;ln++) {
fclose(files[ln]);
}
return 0;
}