perl – 如何快速解析大(> 10GB)文件?
我必须处理格式大小为10-20GB的文本文件:
field1 field2 field3 field4 field5 我想将每行field2中的数据解析成几个文件中的一个;推送到的文件是由field4中的值逐行确定的. field2中有25个不同的可能值,因此数据可以被解析为25个不同的文件. 我尝试过使用Perl(慢速)和awk(更快但仍然很慢) – 有没有人对替代方法有任何建议或指示? 仅供参考,这是我试图使用的awk代码;注意我必须恢复通过大文件25次,因为我无法在awk中同时打开25个文件: chromosomes=(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25) for chr in ${chromosomes[@]} do awk < my_in_file_here -v pat="$chr" '{if ($4 == pat) for (i = $2; i <= $2+52; i++) print i}' >> my_out_file_"$chr".query done 解决方法
这是Python的解决方案.我在一个我编写的小文件上测试了它.我认为即使是大文件,这也是可以接受的,因为大部分工作都是由Python内部的C代码完成的.我认为这是一个令人愉快且易于理解的程序;我更喜欢Python到Perl.
import sys s_usage = """ Usage: csplit <filename> Splits input file by columns,writes column 2 to file based on chromosome from column 4.""" if len(sys.argv) != 2 or sys.argv[1] in ("-h","--help","/?"): sys.stderr.write(s_usage + "n") sys.exit(1) # replace these with the actual patterns,of course lst_pat = [ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y' ] d = {} for s_pat in lst_pat: # build a dictionary mapping each pattern to an open output file d[s_pat] = open("my_out_file_" + s_pat,"wt") if False: # if the patterns are unsuitable for filenames (contain '*','?',etc.) use this: for i,s_pat in enumerate(lst_pat): # build a dictionary mapping each pattern to an output file d[s_pat] = open("my_out_file_" + str(i),"wt") for line in open(sys.argv[1]): # split a line into words,and unpack into variables. # use '_' for a variable name to indicate data we don't care about. # s_data is the data we want,and s_pat is the pattern controlling the output _,s_data,_,s_pat,_ = line.split() # use s_pat to get to the file handle of the appropriate output file,and write data. d[s_pat].write(s_data + "n") # close all the output file handles. for key in d: d[key].close() 编辑:这里有关于这个程序的更多信息,因为它似乎你将使用它. 所有错误处理都是隐含的.如果发生错误,Python将“引发异常”,这将终止处理.例如,如果其中一个文件无法打开,该程序将停止执行,Python将打印一个回溯,显示哪行代码导致异常.我可以用“try / except”块包装关键部分,以捕获错误,但对于一个简单的程序,我没有看到任何意义. 它很微妙,但有一个检查,看输入文件的每一行是否正好有五个单词.当这段代码解包一行时,它会分为五个变量. (变量名称“_”是一个合法的变量名称,但是Python社区中有一个约定将它用于您实际上并不关心的变量.)如果不存在五个单词,Python将引发异常.输入行解压缩成五个变量.如果您的输入文件有时可以在一行上有四个单词,或者六行或更多,您可以修改程序以不引发异常;将主循环更改为: for line in open(sys.argv[1]): lst = line.split() d[lst[3]].write(lst[1] + "n") 这会将行拆分为单词,然后将整个单词列表分配到单个变量lst中.所以这行代码并不关心行上有多少个单词.然后下一行索引到列表中以获取值.由于Python使用0开始索引列表,因此第二个单词是lst [1],第四个单词是lst [3].只要列表中至少有四个单词,该行代码也不会引发异常. 当然,如果该行的第四个单词不在文件句柄的字典中,Python也会为此引发异常.这将停止处理.下面是一些如何使用“try / except”块来处理这个问题的示例代码: for line in open(sys.argv[1]): lst = line.split() try: d[lst[3]].write(lst[1] + "n") except KeyError: sys.stderr.write("Warning: illegal line seen: " + line) 祝你的项目好运. 编辑:@larelogio指出此代码与AWK代码不匹配. AWK代码有一个额外的for循环,我不明白.这是Python代码做同样的事情: for line in open(sys.argv[1]): lst = line.split() n = int(lst[1]) for i in range(n,n+53): d[lst[3]].write(i + "n") 这是另一种方法.这可能会快一点,但我没有测试过,所以我不确定. for line in open(sys.argv[1]): lst = line.split() n = int(lst[1]) s = "n".join(str(i) for i in range(n,n+53)) d[lst[3]].write(s + "n") 这将构建一个包含要写入的所有数字的字符串,然后将它们写入一个块中.与调用.write()53次相比,这可以节省时间. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |