2012-10-03 40 views
3

存在很多解决方案,但这里的特殊性是我需要能够在一行内分割,剪切应该在模式之前发生。例如:根据模式将一个文件分割成多个文件(可以在行内发生切割)

INFILE:

<?xml 1><blabla1> 
<blabla><blabla2><blabla> 
<blabla><blabla> 
<blabla><blabla3><blabla><blabla> 
<blabla><blabla><blabla><?xml 4> 
<blabla> 
<blabla><blabla><blabla> 
<blabla><?xml 2><blabla><blabla> 

应与模式成为<?xml

Outfile1:

<?xml 1><blabla1> 
<blabla><blabla2><blabla> 
<blabla><blabla> 
<blabla><blabla3><blabla><blabla> 
<blabla><blabla><blabla> 

Outfile2:

<?xml 4> 
<blabla> 
<blabla><blabla><blabla> 
<blabla> 

Outfile3:

<?xml 2><blabla><blabla> 

其实perl脚本的验证答案here我的小例子正常工作。但它会为我的更大(约6GB)实际文件生成一个错误。错误是:

panic: sv_setpvn called with negative strlen at /home/.../split.pl line 7, <> chunk 1. 

我没有权限评论,这就是为什么我开始一个新的职位。 最后,一个Python解决方案将更受赞赏,因为我更了解它。

回答

8

这不读一切到RAM中执行分裂:

def files(): 
    n = 0 
    while True: 
     n += 1 
     yield open('/output/dir/%d.part' % n, 'w') 


pat = '<?xml' 
fs = files() 
outfile = next(fs) 

with open(filename) as infile: 
    for line in infile: 
     if pat not in line: 
      outfile.write(line) 
     else: 
      items = line.split(pat) 
      outfile.write(items[0]) 
      for item in items[1:]: 
       outfile = next(fs) 
       outfile.write(pat + item) 

一句警告:这不,如果你的模式利差工作跨越多行(即包含“\ n”)。如果是这种情况,请考虑mmap solution

+0

易于理解且非常高效。谢谢! – LostInTranslation

+0

@LostInTranslation:谢谢,但请参阅编辑 – georg

+0

行。那不是我的情况。唯一的(小问题)是它创建了第一个空文件。 – LostInTranslation

0

只是做一个分裂您的搜索字词

for i,part in enumerate(my_xml_Text_string.split("<?xml")): 
    if not part.strip():continue # make sure its not empty 
    with open("file%d.xml"%i,"w") as f: #open a file to write to 
     f.write("<?xml"+part) #write the content putting your search term back in 
+0

请解释你的答案。此答案出现在“低质量帖子”列表中。 –

+0

我希望你不是建议my_xml_Text_string将包含一个6GB的字符串? –

+0

是的我猜我的选择性愿景忽略了备忘录的一部分:P –

4

对于这种大小的文件,您可能需要使用mmap模块,因此您不必亲自处理文件分块。从那里的文档:

内存映射文件对象的行为像两个字符串和像文件 对象。不像普通的字符串对象,但是,它们是可变的。您可以在大多数需要字符串的地方使用mmap对象,您可以使用 ;例如,对于 示例,可以使用re模块搜索内存映射的 文件。由于它们是可变的,因此可以通过 更改单个字符,或者通过分配给片来更改子字符串: obj[i1:i2] = '...'。您还可以读取和写入从 当前文件位置开始的数据,并通过文件将seek()写入不同的 位置。

下面是一个快速示例,向您展示如何在文件中查找每个出现的<?xml #>。您可以随时将这些块写入新文件,但我没有写入该部分。

import mmap 
import re 

# a regex to match the "xml" nodes 
r = re.compile(r'\<\?xml\s\d+\>') 

with open('so.txt','r+b') as f: 
    mp = mmap.mmap(f.fileno(),0) 
    for m in r.finditer(mp): 
     # here you can start collecting the starting positions and 
     # writing chunks to new files 
     print m.start() 
+0

我喜欢这个解决方案,看起来很聪明。由于我必须在一个python程序中处理它,它可以对分割文件做一些事情,我想我可以给它一个mmap而不是文件列表。我唯一的问题是处理起来有点难,不是那么简单。 – LostInTranslation

6

Perl可以逐行解析大文件,而不是将整个文件拖入内存。 这里是一个简短的脚本(有解释):

perl -n -E 'if (/(.*)(<\?xml.*)/) { 
    print $fh $1 if $1; 
    open $fh, ">output." . ++$i; 
    print $fh $2; 
} else { print $fh $_ }' in.txt 

perl -n:本-n标志由线环在你的文件行(设置内容,$ _)

-E:执行以下文本(Perl默认为文件名)

if (/(.*)(<\?xml.*))如果一行匹配<?xml将该行(使用正则表达式匹配)划分为$ 1和$ 2。

print $fh $1 if $1将行的开头打印到旧文件。

open $fh, ">output.". ++$i;创建一个新的文件句柄来写入。

print $fh $2将该行的其余部分打印到新文件中。

} else { print $fn $_ }如果行不匹配<?xml只是打印到当前文件句柄。

注意:此脚本假设您的输入文件以<?xml开头。

相关问题