存在很多解决方案,但这里的特殊性是我需要能够在一条线内分割,切割应该在模式之前发生。例如:
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>
实际上,经验证的答案here中的perl
脚本适用于我的小例子。但它会为我更大(约6GB)的实际文件生成错误。错误是:
panic: sv_setpvn called with negative strlen at /home/.../split.pl line 7, <> chunk 1.
我没有评论的权限,这就是我开始发布新帖子的原因。
最后,我更了解Python
解决方案,因为我理解得更好。
答案 0 :(得分:9)
执行拆分而不将所有内容读入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。
答案 1 :(得分: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
开头。
答案 2 :(得分:5)
对于那个大小的文件,您可能希望使用mmap
模块,因此您不必自己处理文件分块。从那里的文档:
内存映射文件对象的行为类似于字符串和类似文件 对象。然而,与普通的字符串对象不同,这些是可变的。您 可以在大多数需要字符串的地方使用mmap对象;对于 例如,您可以使用re模块搜索内存映射 文件。由于它们是可变的,你可以改变单个字符 执行
obj[index] = 'a'
,或通过分配切片来更改子字符串: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()
答案 3 :(得分: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